爬虫学习日记1

理解URL

一、URI

什么是uri?web上每种可用资源,如html文档、图像、视频、程序等都是由一个通用资源标志符URI(Universal Resource Identifer)进行定位。

URI通常由三部分组成:

  1. 访问资源的命名机制;
  2. 存放资源的主机名;
  3. 资源自身的名称,由路径表示。

如下面的URI:

http://www.webmonkey.com.cn/html/html40/

我们可以这样理解:这是一个通过HTML协议访问的资源,位于主机www.webmonkey.com.cn上,通过路径“/html/html40”访问。

二、URL

URL是URI的一个子集。是统一资源定位符(Universal Resource Locator)的缩写,URL是Internet上描述信息资源的字符串,主要用在各种WWW客户程序和服务器程序上。

URL的格式由三部分组成:

  1. 协议(或称为服务方式)
  2. 存有该资源的主机IP地址(有时包括端口)
  3. 主机资源的具体地址,如目录和文件名

HTTP协议的URL示例

例:http://www.baidu.com/talk/talk.htm

其计算机域名为www.baidu.com,超级文本文件(文件类型为".html")是在目录"/talk"下的"talk.htm"

文件的URL

例:file://ftp.youku.com/pub/files/foobar.txt

上面这个URL代表存放在主句file://ftp.youku.com上的"pub/files/"目录下的一个文件,文件名为"foobar.txt"。

通过URL抓取网页内容

上面讲了URL的构成,下面主要阐述根据URL抓取网页。所谓网页抓取就是把URL地址重指定的网络资源从网络流中读取出来,然后保存到本地。类似于使用程序模拟浏览器功能,把URL作为HTTP请求的内容发送到服务器,然后读取服务器的响应资源。

GET方式:

  1. 通过URL地址获取URL对象

    java.net.URL url=new URL(path);

  2. 通过URL对象获取网络流

    InputStream stream=url.openStream();

在实际项目中,网络环境比较复杂,只用java.net包中的API来模拟浏览器客户端的工作代码量非常大,需要处理HTTP返回的状态码,设置HTTP代理,处理HTTPS协议等工作,为了便于应用程序的开发,实际开发时常常使用Apache的HTTP客户端开源项目HttpClient。例如:

  1. 创建一个客户端,类似打开一个浏览器

    HttpClient httpClient=new org.apache.commons.httpclient.HttpClient();

  2. 创建一个get方法,类似于在浏览器地址中输入一个地址

    GetMethod getMethod=new org.apache.commons.httpclient.methods.GetMethod(path);//path为URL字符串

  3. 执行,返回响应状态码

    int statusCode = httpClient.executeMethod(getMethod);

  4. 只处理状态码为200(请求成功)的请求

    statusCode == HttpStatus.SC_OK

  5. 获取请求返回的内容流

    InputStream input = getMethod.getResponseBodyAsStream();

  6. 获取文件输出流

    String filename ="输出路径"+输出文件名;

    OutputStream output = new FileOutputStream(filename);

  7. 输出到文件

    int tempByte = -1;

    while ((tempByte = input.read()) > 0) {

    output.write(tempByte);

    }

  8. 关闭输入输出流

    input.close();

    output.close();

下面代码可直接运行:

package spider;

import java.io.FileOutputStream;

import java.io.InputStream;

import java.io.OutputStream;

import org.apache.commons.httpclient.HttpClient;

import org.apache.commons.httpclient.HttpStatus;

import org.apache.commons.httpclient.methods.GetMethod;

/**

*

* @author CallMeWhy

*

*/

public class Spider {

private static HttpClient httpClient = new HttpClient();

/**

* @param path

*            目标网页的链接

* @return 返回布尔值,表示是否正常下载目标页面

* @throws Exception

*             读取网页流或写入本地文件流的IO异常

*/

public static boolean downloadPage(String path) throws Exception {

// 定义输入输出流

InputStream input = null;

OutputStream output = null;

// 得到 post 方法

GetMethod getMethod = new GetMethod(path);

// 执行,返回状态码

int statusCode = httpClient.executeMethod(getMethod);

// 针对状态码进行处理

// 简单起见,只处理返回值为 200 的状态码

if (statusCode == HttpStatus.SC_OK) {

input = getMethod.getResponseBodyAsStream();

// 通过对URL的得到文件名

String filename = path.substring(path.lastIndexOf(‘/‘) + 1)

+ ".html";

// 获得文件输出流

output = new FileOutputStream(filename);

// 输出到文件

int tempByte = -1;

while ((tempByte = input.read()) > 0) {

output.write(tempByte);

}

// 关闭输入流

if (input != null) {

input.close();

}

// 关闭输出流

if (output != null) {

output.close();

}

return true;

}

return false;

}

public static void main(String[] args) {

try {

// 抓取百度首页,输出

Spider.downloadPage("https://www.baidu.com");

} catch (Exception e) {

e.printStackTrace();

}

}

}

POST方式:

package spider;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import org.apache.commons.httpclient.HttpClient;

import org.apache.commons.httpclient.HttpException;

import org.apache.commons.httpclient.HttpStatus;

import org.apache.commons.httpclient.NameValuePair;

import org.apache.commons.httpclient.methods.PostMethod;

public class PostSpider {

private static HttpClient httpClient=new HttpClient();

//设置代理服务器

static{

//代理服务器IP地址和端口

httpClient.getHostConfiguration().setProxy("127.0.0.1", 8080);

}

public static boolean downloadPage(String path) throws HttpException,IOException{

boolean flag=false;

InputStream input=null;

OutputStream output=null;

PostMethod postMethod=new PostMethod(path);

//设置post方法的参数

NameValuePair[] postData=new NameValuePair[2];

postData[0]=new NameValuePair("name","xxxxxx");

postData[1]=new NameValuePair("password","xxxxxx");

postMethod.addParameters(postData);

//执行 返回状态码

int statusCode=httpClient.executeMethod(postMethod);

//针对状态码进行处理(也可以处理其它状态码,这里只处理200的状态码)

if(statusCode==HttpStatus.SC_OK){

input=postMethod.getResponseBodyAsStream();

//文件名

String filename = path.substring(path.lastIndexOf(‘/‘) + 1)

+ ".html";

//获得文件输出流

output=new FileOutputStream(filename);

//输出到文件

int tempByte=-1;

while((tempByte=input.read())>0){

output.write(tempByte);

}

//关闭输入输出流

if(input!=null){

input.close();

}

if(output!=null){

output.close();

}

flag=true;

}

return flag;

}

public static void main(String[] args) {

try {

PostSpider.downloadPage("https://www.baidu.com");

} catch (Exception e) {

e.printStackTrace();

}

}

}

上面需要改动的是代理服务器、参数

时间: 2024-11-03 21:52:29

爬虫学习日记1的相关文章

java爬虫学习日记2-宽度优先爬虫代码实现

爬虫两种方式--宽度优先和带偏好爬虫 先复习下上次学了什么: URL和URI的结构组成 根据指定网址爬取网站内容(get方式和post方式) 上一日记中学到了抓取单个页面内容的方法,但实际项目中则需要爬虫遍历互联网,把互联网中相关的页面都抓取回来.那么爬虫是怎样遍历互联网,把页面抓取下来的呢?首先互联网可以开成是一个"图",每个页面可以看作一个节点,链接可以看作是"有向边".因此能够通过图的方式对互联网这超级大"图"进行遍历.图的遍历通常可分为宽

学习日记之状态模式和Effective C++

状态模式(State):当一个对象内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类. (1),状态模式主要负责解决的是当控制一个对象转换的条件表达式过于复杂时的情况.把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化. (2),状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来. (3),将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易地增加新的状态和

学习日记

五一耍了三天,自己的计划有泡汤,那种制止力哪里去了,不过我认真起来还有有废寝忘食的时候,不过希望这种时候多一点,回家妈妈告诉我,她给老师打电话了的,老师说了我的一些情况,不过我没有老师说的那么好,学习在班上算中等.我觉得还算不上吧!任重而道远吧. Java中有个比较重要的类Properties(Java.util.Properties),主要用于读取Java的配置文件,各种语言都有自己所支持的配置文件,配置文件中很多变量是经常改变的,这样做也是为了方便用户,让用户能够脱离程序本身去修改相关的变量

学习日记之解释器模式和Effective C++

解释器模式(interpreter):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. (1),如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言的句子.这样可以构建一个解释器,该解释器通过解释这些句子来解决该问题. (2),当一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象的语法树时,可使用解释器模式. (3),容易改变和扩展文法,因为该模式使用类来表示文法规则,你可以使用继承来改变和扩展该文法

学习日记之中介者模式和Effective C++

中介者模式(Mediator):用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变他们之间的交互. (1),中介者模式很容易在系统中应用,也很容易在系统中误用.当系统出现多对多交互复杂的对象群时,不要急于使用中介者模式,而要反思你在系统的设计上是不是合理. (2),中介者的出现减少了各个对象的耦合,使得可以独立地改变和复用各个对象和中介者. (3),由于把对象如何协作进行了抽象,将中介者作为一个独立的概念并将其封装在一个对象中,这样关注

学习日记之职责链模式和Effective C++

职责链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这个对象连成一条链,并沿着该条链传递该请求,直到有一个对象处理它为止. (1),当客户提交一个请求时,请求时沿着链传递直到有一个 ConcreteHandler 对象负责处理它. (2),接收者和发送者都没有对方的明确信息,切链中的对象自己也不知道链的结构.结果是职责链可简化为对象之间的连接,它们仅需保留一个指向其后继者的引用.而不惜保留它所有的候选接收者的引用

学习日记之单例模式和Effective C++

单例模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点. (1),通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象.一个最好的办法就是,让类自身负责保存它的唯一实例.这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法. (2),lock 是确保当一个线程位于代码的临界区时,另一个线程不进入临界区.如果其他线程试图进入锁定的代码,则它将一直等待,知道该对象被释放. (3),双重锁定解决效率问题. (4),C#与公共语言运行库

学习日记之迭代器模式和Effective C++

迭代器模式(Iterator):提供一种方法顺序访问一个聚合对象的各个元素,而又不暴露该对象的内部表示. (1),当需要访问一个聚合对象,而且不管这些对象是什么都需要遍历的时候,你就应该考虑迭代器模式. (2),你需要对聚集有多种方式遍历时,可以考虑用迭代器模式. (3),当遍历不同的聚集结构,应提供如开始.下一个.当前项等统一的接口. (4),迭代器模式就是分离了集合对象的遍历行为,抽象出一个迭代器来负责,这样即可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据. Effec

学习日记之适配器模式和Effective C++

适配器模式(Adapter):将一个类的接口转换为客户希望的另一个接口.Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. (1),系统的数据和行为都正确,但接口不符时,我们应该考虑适配器模式,目的是使控制范围之外的一个原有对象与某个接口匹配.适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况. (2),使用一个已经存在的类,但如果他的接口,也就是他的方法和你的要求不相同时,经营该考虑适配器模式. (3),两个类所做的事情相同或相似,但是具