-
2022-03-24 01:13:29
Java网络爬虫基础
Http基础
网络资源一般是Web服务器上的一些各种格式的文件,通过Http协议传输互联网上的数据.
在Java中,通常通过URL标出网络资源的位置和Web服务器建立链接,获取网页源代码.
爬虫程序通过域名服务(Domain Name Serive,简称 DNS)取得域名对应的IP地址,它首先连接到一个DNS服务器上,由DNS服务器返回域名对应的IP地址.DNS把解析到错误的域名叫做DNS劫持.Linux常用如下命令来分析DNS解析的问题(以下命令暂以百度为例)
$ dig www.baidu.com ; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.5 <<>> www.baidu.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60412 ;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;www.baidu.com. IN A ;; ANSWER SECTION: www.baidu.com. 419 IN CNAME www.a.shifen.com. www.a.shifen.com. 149 IN A 110.242.68.3 www.a.shifen.com. 149 IN A 110.242.68.4 ;; Query time: 1 msec ;; SERVER: 183.60.83.19#53(183.60.83.19) ;; WHEN: Wed Mar 23 22:16:36 CST 2022 ;; MSG SIZE rcvd: 90
$ nslookup www.baidu.com Server: 183.60.83.19 Address: 183.60.83.19#53 Non-authoritative answer: www.baidu.com canonical name = www.a.shifen.com. Name: www.a.shifen.com Address: 110.242.68.4 Name: www.a.shifen.com Address: 110.242.68.3
在Windows下可以以如下方法查看路由情况.
> tracert -d www.baidu.com 通过最多 30 个跃点跟踪 到 www.a.shifen.com [110.242.68.3] 的路由: 1 <1 毫秒 <1 毫秒 1 ms 192.168.1.1 2 1 ms 1 ms 1 ms 192.168.18.1 3 4 ms 3 ms 2 ms 111.161.232.1 4 3 ms 2 ms 2 ms 117.8.159.205 5 3 ms 3 ms 3 ms 117.10.223.117 6 * * * 请求超时。 7 9 ms 9 ms 9 ms 110.242.66.186 8 * * * 请求超时。 9 * * * 请求超时。 10 * * * 请求超时。 11 * * * 请求超时。 12 * * * 请求超时。 13 9 ms 9 ms 9 ms 110.242.68.3 跟踪完成。
通过Java来获取一个网站所有的IP
import java.net.InetAddress; import java.util.ArrayList; import java.util.List; public class Main { public static void main(String[] args) { try { List<String> ipList = new ArrayList<>(); InetAddress[] addressesList = InetAddress.getAllByName("www.sina.com.cn"); for(InetAddress address:addressesList) { ipList.add(address.getHostAddress()); System.out.println(address.getHostAddress()); } }catch (Exception e){e.printStackTrace();} } }
URL可选择一个指定的端口,它用于建立远程主机TCP(Transmission Control Protocol)连接的端口号,如果未指定端口则默认使用默认端口,80端口.
URI
URI包括URL和URN,但是URN并不常用.URL由3部分组成:
https://finance.sina.com.cn/stock/ 协议名 主机名 资源路径 http finance.sina.com.cn stock Http规范定义了8种可能的请求方法,爬虫经常用到的有以下三种:
方法 说明 GET 检索URI种标识资源的一个简单请求 HEAD 与GET方法相同,服务器只返回状态行和头标,不返回请求文档 POST 服务器接受被写入客户端输出流中的数据的请求,可以用POST方法来提交表单参数 发送给Web服务器的请求头参数
请求头参数 含义 Accept:text/plain,text/html 说明了可以接收文本类型的信息 Referer:https://www.sina.com.cn/ 此值告诉服务器访问来自于哪个页面,服务器由此可以获得一些信息用于处理,有的网站会利用此参数用于防止图片盗链 Keep-alive:115 是指在同一个链接中发出和接收多次HTTP请求 Web服务器处理返回的状态码分类
状态码 类型 作用 1xx 信息响应类 表示接收到请求并且继续处理 2xx 处理成功响应类 表示动作被成功接收、理解和接受 3xx 重定向响应类 为了完成指定动作,必须接受进一步处理 4xx 客户端错误 客户端请求包含语法错误或者不能正确执行 5xx 服务端错误 服务器不能正确执行一个正确的请求 HTTP常用状态码
状态代码 代码描述 处理方式 200 请求成功 获得响应的内容,进行处理 201 请求完成,结果是创建了新资源.新创建资源的URI可在响应的实体中得到 爬虫不会遇到 202 请求被接受,但处理尚未完成 阻塞等待 204 服务器端已经实现了请求,但没有返回新的信息,如果客户是用户代理,则无须为此更新自身的文档视图 丢弃 300 该状态码不被HTTP/1.0的应用程序直接使用,只是作为3xx类型回应的默认解释,存在多个可用的被请求资源 若程序中能够处理,则进行进一步处理,如果程序中不能处理,则丢弃 301 请求到的资源都会分配一个永久的URL,这样就可以在将来通过该URL来访问此资源 重定向到分配的URL 302 请求到的资源在一个不同的URL处临时保存 重定向到临时的URL 304 请求的资源未更新 丢弃 400 非法请求 丢弃 401 未授权 丢弃 403 禁止 丢弃 404 没有找到 丢弃 500 服务器内部错误 丢弃 502 错误网关 丢弃 503 服务器暂时不可用 丢弃 Get Post Head方法的基础Java代码
Maven依赖:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.3</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.5.3</version> </dependency>
Head:
import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpHead; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import java.net.URI; public class Head { private String url=""; public void setUrl(String url) { this.url=url; } public void doHead() throws Exception { CloseableHttpClient closeableHttpClient= HttpClientBuilder.create().build(); URI uri=new URI(url); HttpHead method=new HttpHead(uri); HttpResponse response=closeableHttpClient.execute(method); Header[] s=response.getAllHeaders(); for(int i=0;i<s.length;i++) { Header hd=s[i]; System.out.println("Header Name: "+hd.getName()+" "+"Header Value: "+hd.getValue()); } } }
Get:
import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; import java.util.HashMap; import java.util.Map; import java.util.Set; public class Get { private String url=""; public void setUrl(String url) { this.url=url; } private String cookie=""; public void setCookie(String cookie) { this.cookie=cookie; } private Map header=new HashMap(); public void addHeader(String key,String value) { header.put(key,value); } private String html=""; public String doGet() throws Exception { CloseableHttpClient closeableHttpClient= HttpClientBuilder.create().build(); HttpGet httpGet=new HttpGet(url); /* 传参 */ // httpGet.addHeader("User-Agent","Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"); // httpGet.setHeader("Cookie","HttpOnly; UM_distinctid=176d650b687fc-0a035a289264ec-1e2e1b0b-1fa400-176d650b688c77; Hm_lvt_080dabacb001ad3dc8b9b9049b36d43b=1609913383; f_city=%E5%A4%A9%E6%B4%A5%7C101030100%7C; Wa_lvt_1=1609913383; CNZZDATA1278536588=1934037795-1609908526-%7C1609918974"); Set<Map.Entry<String,String>> entrySet=header.entrySet(); for(Map.Entry<String,String> entryset:entrySet) { httpGet.setHeader(entryset.getKey(),entryset.getValue()); } HttpResponse response=closeableHttpClient.execute(httpGet); HttpEntity entity=response.getEntity(); if(entity!=null) { html= EntityUtils.toString(entity,"UTF-8"); EntityUtils.consume(entity); } return html; } }
Post:
import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.ByteArrayBuffer; import java.io.BufferedInputStream; import java.io.InputStream; import java.util.*; public class Post { private String url=""; public void setUrl(String url) { this.url=url; } private String cookie=""; public void setCookie(String cookie) { this.cookie=cookie; } private Map<String,String> header=new HashMap<>(); public void addHeader(String key,String value) { header.put(key,value); } private List<NameValuePair> nameValuePairs=new ArrayList<NameValuePair>(); public void addNameValuePairs(String key,String value) { nameValuePairs.add(new BasicNameValuePair(key,value)); } public String doPost() throws Exception { CloseableHttpClient httpClient= HttpClientBuilder.create().build(); HttpPost httpPost=new HttpPost(url); Set<Map.Entry<String,String>> entrySet=header.entrySet(); for(Map.Entry<String,String> entryset:entrySet) { httpPost.setHeader(entryset.getKey(),entryset.getValue()); } /* 传参 */ // httpPost.setHeader("Content-Type","application/x-www-form-urlencoded"); // httpPost.setHeader("Cookie",cookie); // nameValuePairs.add(new BasicNameValuePair("page","1")); // nameValuePairs.add(new BasicNameValuePair("rp","12")); // nameValuePairs.add(new BasicNameValuePair("sortname","_CreateTime")); // nameValuePairs.add(new BasicNameValuePair("sortorder","desc")); // nameValuePairs.add(new BasicNameValuePair("query","")); // nameValuePairs.add(new BasicNameValuePair("qtype","")); // nameValuePairs.add(new BasicNameValuePair("queryid","flowmystart")); // nameValuePairs.add(new BasicNameValuePair("condition","_UserName='53c6b305-5bea-450a-b7a1-11ce1feab4b2'")); httpPost.setHeader("cookie",cookie); httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); HttpResponse response=httpClient.execute(httpPost); HttpEntity entity=response.getEntity(); InputStream inputStream=entity.getContent(); BufferedInputStream bufferedInputStream=new BufferedInputStream(inputStream); ByteArrayBuffer byteArrayBuffer=new ByteArrayBuffer(20); int current=0; while((current=bufferedInputStream.read())!=-1) { byteArrayBuffer.append((byte) current); } String text=new String(byteArrayBuffer.toByteArray()); System.out.println(text); return text; } }
更多相关内容 -
JAVA网络爬虫
2019-07-22 14:10:49Java网络爬虫目录------------01.爬虫的介绍------------02.HttpClient------------03.Jsoup解析------------------------04.爬虫案例------------05.WebMagic------------06.案例实现------------------------07.... -
Java-Carwler-Technology:网络数据采集技术—Java网络爬虫 (书稿完整代码,涉及网络爬虫的各种技术和知识点...
2021-05-13 14:04:40Java网络爬虫 书中的代码,另外本人的介绍了大量的网络爬虫知识,有兴趣的可以学习。 为及时更正书中的不恰当的内容,笔者在CSDN博客中创建了一个页面: 读者可以将书中的问题,以评论的方式反馈给我,笔者针对... -
网络数据采集技术——Java网络爬虫实战
2020-11-02 17:04:17网络数据采集技术——Java -
JAVA网络爬虫实战视频教程
2018-11-20 23:30:34┃ ┣━网络爬虫JAVA ┃ ┃ ┃ ┃ ┣━开源系统-教学视频 ┃ ┃ ┃ ┃ ┃ ┣━微博爬虫-博主、博文、关注列表抓取更新.zip ┃ ┃ ┃ ┃ ┃ ┣━微博爬虫_导入与布署视频.zip ┃ ┃ ┃ ┃ ┃ ┣━漫爬型网络爬虫_导入... -
java 网络爬虫
2017-11-23 16:11:12Java网络爬虫,这个项目是一个在线的项目,可以抓取电话、邮箱、图片地址,可以指定一个网页,程序就可以自动抓取网页中的其他的URL地址,并且放到容器中。然后程序会自动解析容器中的超链接,然后读取资源,解析... -
java网络爬虫实现简单Demo
2016-09-29 20:44:30java网络爬虫实现简单Demo -
Java 网络爬虫基础知识入门解析
2020-08-25 13:36:58主要介绍了Java 网络爬虫基础知识入门解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 -
Java网络爬虫简单实现.pdf
2021-10-30 15:06:07Java网络爬虫简单实现.pdf -
Java网络爬虫蜘蛛源码
2015-05-14 13:31:44该院吗详细的写出lJava网络爬虫蜘蛛源码,可以很好的帮助你实现爬虫,对了解爬虫的整个过程和实现爬虫非常有用 -
java网络爬虫
2019-03-21 14:18:27java网络爬虫,打开就能用,即开即用,可以多多交流。 -
Java 网络爬虫代码例子
2018-12-13 15:53:46Java爬虫代码,例子十分简单,很容易接入,希望能帮助到大家。 -
全栈性能java网络爬虫从入门到精通实战.pdf
2020-05-26 22:14:11全面总结概括爬虫的基本原理以及应用,特别是对java有一定基础的人更容易上手。由于它在业界得到广泛的认可的是爬虫爱好者必备的武功秘籍。 -
JAVA 网络爬虫
2014-05-14 15:00:38这个是我帮国外的一个教授写的,前后写了近两个月,本来不想拿出来的,可最近我的账号没什么积分了,所以就贡献出来了,还真有点舍不得!该系统主要是用来爬取某个固定网站中的数据,其中包含静态网页和动态网页数据... -
Java网络爬虫源码
2018-08-16 12:25:28由于项目需要,特研究了一段时间关于java爬虫的相关技术,发现一个比较好用的爬虫框架--WebMagic,只需少量代码即可实现一个爬虫,本项目就是基于它的一个简单实现,导入项目即可运行,项目只有两个类,一个用于抓取... -
[搜索链接]Java网络爬虫(蜘蛛)源码_zhizhu.zip
2021-12-15 16:26:24[搜索链接]Java网络爬虫(蜘蛛)源码_zhizhu.zip -
java网络爬虫+数据库+jsp+搜索引擎.rar.rar
2020-06-22 09:08:59java网络爬虫+数据库+jsp+搜索引擎.rar.rar -
Java 网络爬虫,就是这么的简单
2019-10-08 08:52:43这是 Java 网络爬虫系列文章的第一篇,如果你还不知道 Java 网络爬虫系列文章,请参看 学 Java 网络爬虫,需要哪些基础知识。第一篇是关于 Java 网络爬虫入门内容,在该篇中我们以采集虎扑列表新闻的新闻标题和...这是 Java 网络爬虫系列文章的第一篇,如果你还不知道 Java 网络爬虫系列文章,请参看 学 Java 网络爬虫,需要哪些基础知识。第一篇是关于 Java 网络爬虫入门内容,在该篇中我们以采集虎扑列表新闻的新闻标题和详情页为例,需要提取的内容如下图所示:
我们需要提取图中圈出来的文字及其对应的链接,在提取的过程中,我们会使用两种方式来提取,一种是 Jsoup 的方式,另一种是 httpclient + 正则表达式的方式,这也是 Java 网络爬虫常用的两种方式,你不了解这两种方式没关系,后面会有相应的使用手册。在正式编写提取程序之前,我先交代一下 Java 爬虫系列博文的环境,该系列博文所有的 demo 都是使用 SpringBoot 搭建的,不管你使用哪种环境,只需要正确的导入相应的包即可。
Jsoup 方式提取信息
我们先来使用 Jsoup 的方式提取新闻信息,如果你还不知道 Jsoup ,请参考 https://jsoup.org/
先建立一个 Springboot 项目,名字就随意啦,在 pom.xml 中引入 Jsoup 的依赖
<dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.12.1</version> </dependency>
好了,接下来我们一起分析页面吧,想必你还没浏览过吧,点击这里浏览虎扑新闻。在列表页中,我们利用 F12 审查元素查看页面结构,经过我们分析发现列表新闻在
<div class="news-list">
标签下,每一条新闻都是一个li
标签,分析结果如下图所示:由于我们前面已经知道了 css 选择器,我们结合浏览器的 Copy 功能,编写出我们
a
标签的 css 选择器代码:div.news-list > ul > li > div.list-hd > h4 > a
,一切都准备好了,我们一起来编写 Jsoup 方式提取信息的代码:/** * jsoup方式 获取虎扑新闻列表页 * @param url 虎扑新闻列表页url */ public void jsoupList(String url){ try { Document document = Jsoup.connect(url).get(); // 使用 css选择器 提取列表新闻 a 标签 // <a href="https://voice.hupu.com/nba/2484553.html" target="_blank">霍华德:夏休期内曾节食30天,这考验了我的身心</a> Elements elements = document.select("div.news-list > ul > li > div.list-hd > h4 > a"); for (Element element:elements){ // System.out.println(element); // 获取详情页链接 String d_url = element.attr("href"); // 获取标题 String title = element.ownText(); System.out.println("详情页链接:"+d_url+" ,详情页标题:"+title); } } catch (IOException e) { e.printStackTrace(); } }
使用 Jsoup 方式提取还是非常简单的,就5、6行代码就完成了,关于更多 Jsoup 如何提取节点信息的方法可以参考 jsoup 的官网教程。我们编写 main 方法,来执行 jsoupList 方法,看看 jsoupList 方法是否正确。
public static void main(String[] args) { String url = "https://voice.hupu.com/nba"; CrawlerBase crawlerBase = new CrawlerBase(); crawlerBase.jsoupList(url); }
执行 main 方法,得到如下结果:
从结果中可以看出,我们已经正确的提取到了我们想要的信息,如果你想采集详情页的信息,只需要编写一个采集详情页的方法,在方法中提取详情页相应的节点信息,然后将列表页提取的链接传入提取详情页方法即可。httpclient + 正则表达式
上面我们使用了 Jsoup 方式正确提取了虎扑列表新闻,接下来我们使用 httpclient + 正则表达式的方式来提取,看看使用这种方式又会涉及到哪些问题?httpclient + 正则表达式的方式涉及的知识点还是蛮多的,它涉及到了正则表达式、Java 正则表达式、httpclient。如果你还不知道这些知识,可以点击下方链接简单了解一下:
正则表达式:正则表达式
Java 正则表达式:Java 正则表达式
httpclient:httpclient
我们在 pom.xml 文件中,引入 httpclient 相关 Jar 包
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.10</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.4.10</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.5.10</version> </dependency>
关于虎扑列表新闻页面,我们在使用 Jsoup 方式的时候进行了简单的分析,这里我们就不在重复分析了。对于使用正则表达式方式提取,我们需要找到能够代表列表新闻的结构体,比如:
<div class="list-hd"> <h4> <a href="https://voice.hupu.com/nba/2485508.html" target="_blank">直上云霄!魔术官方社媒晒富尔茨扣篮炫酷特效图</a></h4></div>
这段结构体,每个列表新闻只有链接和标题不一样,其他的都一样,而且<div class="list-hd">
是列表新闻特有的。最好不要直接正则匹配a
标签,因为a
标签在其他地方也有,这样我们就还需要做其他的处理,增加我们的难度。现在我们了解了正则结构体的选择,我们一起来看看 httpclient + 正则表达式方式提取的代码:/** * httpclient + 正则表达式 获取虎扑新闻列表页 * @param url 虎扑新闻列表页url */ public void httpClientList(String url){ try { CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpGet = new HttpGet(url); CloseableHttpResponse response = httpclient.execute(httpGet); if (response.getStatusLine().getStatusCode() == 200) { HttpEntity entity = response.getEntity(); String body = EntityUtils.toString(entity,"utf-8"); if (body!=null) { /* * 替换掉换行符、制表符、回车符,去掉这些符号,正则表示写起来更简单一些 * 只有空格符号和其他正常字体 */ Pattern p = Pattern.compile("\t|\r|\n"); Matcher m = p.matcher(body); body = m.replaceAll(""); /* * 提取列表页的正则表达式 * 去除换行符之后的 li * <div class="list-hd"> <h4> <a href="https://voice.hupu.com/nba/2485167.html" target="_blank">与球迷亲切互动!凯尔特人官方晒球队开放训练日照片</a> </h4> </div> */ Pattern pattern = Pattern .compile("<div class=\"list-hd\">\\s* <h4>\\s* <a href=\"(.*?)\"\\s* target=\"_blank\">(.*?)</a>\\s* </h4>\\s* </div>" ); Matcher matcher = pattern.matcher(body); // 匹配出所有符合正则表达式的数据 while (matcher.find()){ // String info = matcher.group(0); // System.out.println(info); // 提取出链接和标题 System.out.println("详情页链接:"+matcher.group(1)+" ,详情页标题:"+matcher.group(2)); } }else { System.out.println("处理失败!!!获取正文内容为空"); } } else { System.out.println("处理失败!!!返回状态码:" + response.getStatusLine().getStatusCode()); } }catch (Exception e){ e.printStackTrace(); } }
从代码的行数可以看出,比 Jsoup 方式要多不少,代码虽然多,但是整体来说比较简单,在上面方法中我做了一段特殊处理,我先替换了 httpclient 获取的字符串 body 中的换行符、制表符、回车符,因为这样处理,在编写正则表达式的时候能够减少一些额外的干扰。接下来我们修改 main 方法,运行 httpClientList 方法。
public static void main(String[] args) { String url = "https://voice.hupu.com/nba"; CrawlerBase crawlerBase = new CrawlerBase(); // crawlerBase.jsoupList(url); crawlerBase.httpClientList(url); }
运行结果如下图所示:
使用 httpclient + 正则表达式的方式同样正确的获取到了列表新闻的标题和详情页链接。到此 Java 爬虫系列博文第一篇就写完了,这一篇主要是 Java 网络爬虫的入门,我们使用了 jsoup 和 httpclient + 正则的方式提取了虎扑列表新闻的新闻标题和详情页链接。当然这里还有很多没有完成,比如采集详情页信息存入数据库等。
希望以上内容对你有所帮助,下一篇是模拟登陆相关的,如果你对 Java 网络爬虫感兴趣,不妨关注一波,一起学习,一起进步。
源代码:点击这里
文章不足之处,望大家多多指点,共同学习,共同进步
最后
打个小广告,欢迎扫码关注微信公众号:「平头哥的技术博文」,一起进步吧。
-
java网络爬虫-通过登陆网站携带COOKIE信息爬取网站数据
2019-11-04 11:29:30最近开发用到了爬取题库的功能,直接是无法爬取的,通过分析,发现可以通过账号登陆,携带COOKIE信息爬取网站数据。为了方便交流学习,现将代码公开。 -
java网络爬虫连接超时解决实例代码
2020-08-28 04:37:16主要介绍了java网络爬虫连接超时解决的问题,分享了一则使用httpclient解决连接超时的Java爬虫实例代码,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下 -
Java网络爬虫简介
2021-03-27 18:40:21网络爬虫(Web crawler)也叫网络蜘蛛(Web spide)自动检索工具(automatic indexer),是一种”自动化浏览网络“的程序,或者说是一种网络机器人。 爬虫被广泛用于互联网搜索引擎或其他类似网站,以获取或更新这些...一、爬虫介绍
1. 概述
网络爬虫(Web crawler)也叫网络蜘蛛(Web spide)自动检索工具(automatic indexer),是一种”自动化浏览网络“的程序,或者说是一种网络机器人。
爬虫被广泛用于互联网搜索引擎或其他类似网站,以获取或更新这些网站的内容和检索方式。
它们可以自动采集所有其能够访问到的页面内容,以供搜索引擎做进一步处理(分检整理下载的页面),而使得用户能更快的检索到他们需要的信息。
2. 应用
2.1 搜索引擎
爬虫程序可以为搜索引擎系统爬取网络资源,用户可以通过搜索引擎搜索网络上一切所需要的资源。
搜索引擎是一套非常庞大且精密的算法系统,搜索的准确性,高效性等都对搜索系统有很高的要求。
2.2 数据挖掘
爬虫除了用来做搜索外,还可以做非常多的工作,可以说爬虫现在在互联网项目中应用的非常广泛。
互联网项目通过爬取相关数据主要进行数据分析,获取价值数据。
3. 爬虫原理
2.1 框架设计图
基本工作流程如下:
1. 选取种子URL;
2. 将种子URL放入待抓取URL队列;
3. 从待抓取URL队列中取出待抓取在URL;
4. 解析DNS,并且得到主机的ip;
5. 下载URL对应的网页,存储入库;
6. 将抓取完成URL放进已抓取URL队列;
7. 分析已抓取URL队列中的URL,分析网页中的其他URL,并且将URL放入待抓取URL队列;
8. 从而进入下一个循环;2.2 Java爬虫框架
框架 说明 Nutch Nutch 属于分布式爬虫,爬虫使用分布式,主要是解决两个问题:1. 海量数据, 2. 网速。做搜索引擎,Nutch 1.x 是一个非常好的选择,Nutch 1.x 和 solr 或 es 配合,就可以构成一个非常强大的搜索引擎。 但 Nutch 进行爬虫的二次开发所需的编写和调试时间比其他单机爬虫十倍不止。 Heritrix Hetritrix 是个 " Archival Crawler ",来获取完整的、精确的、站点内容的深度复制。包括获取图像以及其他非文本内容,抓取并存储相关的内容,对内容不做过滤,也不对页面内容进行修改,重新爬取相同的URL不会对先前的进行替换。爬虫主要通过Web用户界面启动、监控和调整,允许弹性的定义要获取的url。 Crawler 4j Crawler 4j 是Java实现的开源网络爬虫。提供了简单的接口,可以在几分钟内时实现一个多线程的网络爬虫 WebCollector WebCollector 使用了 Nutch 的爬取逻辑(分层广度遍历)、Crawler 4j 的用户接口(覆盖 visit方法,定义用户操作),以及一套自己的插件机制,设计了一套爬虫内核 WebMagic WebMagic 代码分为核心和扩展两部分,核心部分(WebMagic-Core)是一个精简的、模块化的爬虫实现;而扩展部分则包括一些便利的、实用性的功能。WebMagic 的架构设计参照了Scrapy,目标是尽量的模块化,并体现爬虫的功能特点。 4. HttpClient & Jsoup
4.1 HttpClient简介
HttpClient 是 apache 组织下面的一个用于处理 HTTP 请求和响应的开源工具。它不是一个浏览器,也不处理客户端缓存等浏览器的功能。它只是一个类库!它在 JDK 的基本类库基础上做了更好的封装。
HttpClient 项目依赖于 HttpCore(处理核心的 HTTP 协议)、commons-codec(处理与编码有关的问题的项目)和 commons-logging(处理与日志记录有关问题的项目)。
如果希望能够通过 HttpClient 向服务器上传文件等与 multipart 编码类型有关的请求,以及其它复杂的MIME 类型,那么,需要另外一个依赖包:HttpMime(它是专门处理与 MIME 类型有关问题的项目)。
在下载的 HttpClient 包中(下载地址为:http://hc.apache.org/downloads.cgi)已经包含了 HttpMime。
4.2 HttpClient抓取网页流程
使用HttpClient发送请求、接收响应:
- 创建HttpClient对象。
- 创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;发送POST请求,创建HttpPost对象。
- 需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HetpParams params)方法来添加请求参数;对于HttpPost对象而言,可调用setEntity(HttpEntity entity)方法来设置请求参数。
- 调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse。
- 调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。
- 释放连接。
4.3 HttpClient Demo
import java.io.IOException; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.params.ConnRouteParams; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.CoreConnectionPNames; import org.apache.http.util.EntityUtils; public class MyHttpClient { /*** * 需求:使用httpClient爬取传智播客官方网站数据 * @param args * @throws Exception * @throws ClientProtocolException */ public static void main(String[] args) throws Exception { //创建HttpClient对象 HttpClient hClient = new DefaultHttpClient(); //设置响应时间,设置传智源码时间,设置代理服务器 hClient.getParams(). setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000) .setParameter(CoreConnectionPNames.SO_TIMEOUT, 10000) .setParameter(ConnRouteParams.DEFAULT_PROXY, new HttpHost("123.151.202.211", 808)); //爬虫URL大部分都是get请求,创建get请求对象 HttpGet hget = new HttpGet("http://www.baidu.com/"); //向传智播客官方网站发送请求,获取网页源码 HttpResponse response = hClient.execute(hget); //EntityUtils工具类把网页实体转换成字符串 String content = EntityUtils.toString(response.getEntity(), "utf-8"); System.out.println(content); } }
4.4 Jsoup 简介
soup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。
它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。
通常在写爬虫程序时,httpClient集合Jsoup共同使用即可实现完美的爬虫系统。
httpClient负责模拟浏览器发送请求,Jsoup负责解析httpClient请求返回的HTML页面,解析获取需要的数据
4.5 Jsoup获取网页流程
- 从 URL,文件或字符串中解析 HTML;
- 使用 DOM 或 CSS 选择器来查找、取出数据;
- 可操作 HTML 元素、属性、文本;
4.6 Jsoup Demo
import java.io.IOException; import org.jsoup.Connection; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; public class MyJsoup { /* * 使用Jsoup解析网页源码 */ public static void main(String[] args) throws Exception { //使用jsoup向服务器发送请求 Document doc = Jsoup.connect("http://www.baidu.com").get(); //Jsoup使用类型css,Jquery选择器方式获取元素节点 //Elements elements = doc.getElementsByTag("a"); //System.out.println(elements.text()); Elements elements = doc.select("ul.nav a"); //循环元素 for (Element element : elements) { System.out.println(element.text()+":"+element.attr("href")); } } }
-
Java网络爬虫全面教程
2020-11-28 17:03:10Java网络爬虫 这是本文目录 这里写目录标题Java网络爬虫1. HttpClient1.1 Get请求1.2 POST请求1.3 连接池1.4 参数设置2. Jsoup 本文将循序渐进介绍3大爬虫必备技术 HttpClietn(负责请求页面并获得页面) Jsout...Java网络爬虫
这是本文目录
本文将循序渐进介绍3大爬虫必备技术- HttpClietn(负责请求页面并获得页面)
- Jsout(负责解析页面,提取元素)
- WebMagic(Java的一个爬虫框架,利用WebMagic可以整合1、2中的繁琐操作)
WebMagic框架我们留到下一期讲解。
1. HttpClient
使用网络爬虫其实就是要用Java程序去访问Html页面,并对Html页面进行解析,而Java中HttpClient技术可以很好的访问Html页面,实现抓取网页数据的功能。话不多说,我们立即进入HttpClient的学习吧
1.1 Get请求
tips:以下只介绍使用中涉及的对象、方法,至于异常处理请大家实际操作中自己选择处理方式。
// 使用HttpClient之前必须先创建一个对象 CloseableHttpClient httpClient = HttpClients.createDefault(); // 创建Get请求 HttpGet httpGet = new HttpGet("https://www.baidu.com/"); // 使用HttpClient发起请求 CloseableHttpResponse response = httpClient.execute(httpGet); //获取响应 -> 判断响应状态码是否为200 if (response.getStatusLine().getStatusCode() == 200) { //如果为200表示请求成功,获取返回数据 String content = EntityUtils.toString(response.getEntity(), "UTF-8"); System.out.println(content); }
以下代码为可用程序:
public static void main(String[] args) throws IOException { //创建HttpClient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); //创建HttpGet请求 HttpGet httpGet = new HttpGet("https://www.baidu.com/"); CloseableHttpResponse response = null; try { //使用HttpClient发起请求 response = httpClient.execute(httpGet); //判断响应状态码是否为200 if (response.getStatusLine().getStatusCode() == 200) { //如果为200表示请求成功,获取返回数据 String content = EntityUtils.toString(response.getEntity(), "UTF-8"); //打印数据长度 System.out.println(content); } } catch (Exception e) { e.printStackTrace(); } finally { //释放连接 if (response == null) { try { response.close(); } catch (IOException e) { e.printStackTrace(); } httpClient.close(); } } }
请求百度页面时,有时候会出现请求失败的问题,目前博主还没有有效解决方案,不过只要多请求几次即可,大家知道原因的欢迎补充
带参数的Get请求
以百度为例,我们要检索三星S20手机,首先分析百度的URL
https://www.baidu.com/s?wd=三星S20
接下来我们来编写我们的代码,主要方法与上述一致,这里直接给出可用代码
public static void main(String[] args) throws IOException { //创建HttpClient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); //创建HttpGet请求,带参数的地址https://www.baidu.com/s?wd=HttpClient String uri = "https://www.baidu.com/s?wd=三星S20"; HttpGet httpGet = new HttpGet(uri); CloseableHttpResponse response = null; try { //使用HttpClient发起请求 response = httpClient.execute(httpGet); //判断响应状态码是否为200 if (response.getStatusLine().getStatusCode() == 200) { //如果为200表示请求成功,获取返回数据 String content = EntityUtils.toString(response.getEntity(), "UTF-8"); //打印数据长度 System.out.println(content); } } catch (Exception e) { e.printStackTrace(); } finally { //释放连接 if (response == null) { try { response.close(); } catch (IOException e) { e.printStackTrace(); } httpClient.close(); } } }
1.2 POST请求
POST的无参请求与GET请求的使用方式一样,只不过这次创建的时HTTPPOST对象
public static void main(String[] args) throws IOException { //创建HttpClient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); //创建HttpGet请求 HttpPost httpPost = new HttpPost("http://www.itcast.cn/"); CloseableHttpResponse response = null; try { //使用HttpClient发起请求 response = httpClient.execute(httpPost); //判断响应状态码是否为200 if (response.getStatusLine().getStatusCode() == 200) { //如果为200表示请求成功,获取返回数据 String content = EntityUtils.toString(response.getEntity(), "UTF-8"); //打印数据长度 System.out.println(content); } } catch (Exception e) { e.printStackTrace(); } finally { //释放连接 if (response == null) { try { response.close(); } catch (IOException e) { e.printStackTrace(); } httpClient.close(); } } }
带参数的POST请求
在POST请求中,如果需要带参数的话,必须使用一些对象来模拟表单请求
以下为使用的对象
//声明存放参数的List集合 List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("keys", "java")); //创建表单数据Entity UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(params, "UTF-8"); //设置表单Entity到httpPost请求对象中 httpPost.setEntity(formEntity);
可用代码如下:
public static void main(String[] args) throws IOException { //创建HttpClient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); //创建HttpGet请求 HttpPost httpPost = new HttpPost("http://www.itcast.cn/"); //声明存放参数的List集合 List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("keys", "java")); //创建表单数据Entity UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(params, "UTF-8"); //设置表单Entity到httpPost请求对象中 httpPost.setEntity(formEntity); CloseableHttpResponse response = null; try { //使用HttpClient发起请求 response = httpClient.execute(httpPost); //判断响应状态码是否为200 if (response.getStatusLine().getStatusCode() == 200) { //如果为200表示请求成功,获取返回数据 String content = EntityUtils.toString(response.getEntity(), "UTF-8"); //打印数据长度 System.out.println(content); } } catch (Exception e) { e.printStackTrace(); } finally { //释放连接 if (response == null) { try { response.close(); } catch (IOException e) { e.printStackTrace(); } httpClient.close(); } } }
1.3 连接池
通过上述的学习我们发现,每次爬取信息都要创建以此连接,使用完后又得关闭连接。因此我们使用连接池技术,避免频繁的创建销毁,提高爬取效率。话不多说,进入代码的学习。
- 创建连接池
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
- 从连接池中获取连接
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();
1.4 参数设置
//创建HttpClient对象 RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(1000)//设置创建连接的最长时间 .setConnectionRequestTimeout(500)//设置获取连接的最长时间 .setSocketTimeout(10 * 1000)//设置数据传输的最长时间 .build();
2. Jsoup
通过HttpClient,我们可以轻松的抓取网页了,那么得到网页后,我们该如何解析呢,这个时候Jsoup就登场了。
jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。 jsoup的主要功能如下: 1.从一个URL,文件或字符串中解析HTML; 2.使用DOM或CSS选择器来查找、取出数据; 3.可操作HTML元素、属性、文本;
使用Maven工程导入Jsoup依赖:
<!--Jsoup--> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.10.3</version> </dependency> <!--测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!--工具--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.7</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency>
具体的学习我就不放在这里介绍了,由于博主已经掌握了Jsoup方面的知识,且Jsoup官方API已经有很不错的教程,大家可以到官方中文网站学习,这是学习地址:https://www.open-open.com/jsoup/
如果有需要的话,后面有空我会将这里的教程补充一下。接下来直接进入本文的关键部分,WebMagic爬虫框架