什么是JSOUP
JSOUP 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。 官网
jsoup实现了WHATWG HTML5规范,并将 HTML 解析为与现代浏览器相同的 DOM。
- 从 URL、文件或字符串中抓取和解析HTML
- 使用 DOM 遍历或 CSS 选择器查找和提取数据
- 操作HTML 元素、属性和文本
- 根据安全列表清理用户提交的内容,以防止XSS攻击
- 输出整洁的 HTML
什么是OkHttp
一般在java平台上,我们会使用apache httpclient作为http客户端,用于发送 http 请求,并对响应进行处理。比如可以使用http客户端与第三方服务(如sso服务)进行集成,当然还可以爬取网上的数据等。okhttp与httpclient类似,也是一个http客户端,提供了对 http/2 和 spdy 的支持,并提供了连接池,gzip 压缩和 http 响应缓存功能;
okhttp是目前非常火的网络库,它有以下特性:
1.支持http/2,允许所有同一个主机地址的请求共享同一个socket连接
2.连接池减少请求延时
3.透明的gzip压缩减少响应数据的大小
4.缓存响应内容,避免一些完全重复的请求
爬虫需要掌握的技术
- JSOUP
- OKHTTP
- 前端知识
- http和https
- 数据存储(Json、XML ,txt、html, CSV ,Excel , ES ,mysql,redis…)
- 数据分析
- JavaScript语言
- 抓包工具fiddler,Wireshark
- 数据清洗
- 正则表达式
- 文件读写
- 多线程
根据情况可能还不止上面这些,但是会了上面这些技术那么可以说爬虫算是入门
需要的依赖
<!-- 爬虫-解析html页面-->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.10.0</version>
</dependency>
JSON入门Demo
爬取华北地区,所有省市,一个星期全部的天气
按下f12,就就能查看html的结构进行分析具体该怎么爬,然后找到对应的标签,之后根据标签的位置写出css选择器
具体详情代码如下:
//拿到网页的xml
String doc = OkHttpUtils.builder()
.url("http://www.weather.com.cn/textFC/hb.shtml")
.get()
.sync();
//时间,省市,城市,天气现象
StringBuilder stringBuilder0=new StringBuilder();
//标题
StringBuilder stringBuilder = new StringBuilder("时间,省市,城市,天气现象,风向风力,最高气温,天气现象,风向风力,最低气温");
stringBuilder0.append(stringBuilder).append("\n");
Document document = Jsoup.parse(doc);//将页面转换为Document
//使用css 选择器
Elements selecttop = document.select(".day_tabs li");
//拿到数据列表
Elements select = document.select(".conMidtab");
for (int i1 = 0; i1 < selecttop.size(); i1++) {
Element element = selecttop.get(i1);
String text = element.text();
//进行数据清洗,取出时间
String time = PatternCommon.cutPatternStr(text, "[\\u4e00-\\u9fa5]*\\((\\S*)\\)", 1).get(1);
//取和实际对应的列表
Element element1 = select.get(i1);
Elements midtab = element1.select(".conMidtab2");
for (int i = 0; i < midtab.size(); i++) {
StringBuilder stringBuilder1 = new StringBuilder();
//时间
stringBuilder1.append(time).append(",");
Element element2 = midtab.get(i);
//拿到所有的行
Elements trs = element2.select("table tr");
//拿到省市
Elements select2 = trs.select(".rowspan");
stringBuilder1.append(select2.text()).append(",");
//跳过前3行从第4行开始读取
for (int i2 = 3; i2 < trs.size()-1; i2++) {
StringBuilder stringBuilder2 = new StringBuilder();
Element element3 = trs.get(i2);
//拿到行下所有列 城市,天气现象,风向风力,最高气温,天气现象,风向风力,最低气温
Elements td = element3.select("td");
for (int i3 = 0; i3 < td.size(); i3++) {
Element element4 = td.get(i3);
if(i3 == td.size()-2){
//最后一个不需要逗号
stringBuilder2.append(element4.text());
break;
}
stringBuilder2.append(element4.text()).append(",");
}
StringBuilder stringBuilder3 = new StringBuilder();
stringBuilder3.append(stringBuilder1).append(stringBuilder2);
stringBuilder0.append(stringBuilder3).append("\n");
}
}
}
//将内容按行写入到csv文件中
String absoluteFilePathAndCreate = ResourceFileUtil.getAbsoluteFileOrDirPathAndCreate("/weather.csv");
ReadWriteFileUtils.writeStrCover(new File(absoluteFilePathAndCreate),stringBuilder0.toString());
JSOUP常用方法
注意: 下面的参数名称query和cssQuery 就是css选择器
Jsoup:
- Document Jsoup.parse(str); 将字符串HTML转换为Document
- Connection connect(String url) 创建到URL的新连接。用于获取和解析HTML页面
- Document parse(File in, “UTF-8”) 将文件内容解析为HTML。
- Document parse(InputStream in, “UTF-8”, “”) 读取输入流,并将其解析为HTML。
Document :
- Elements select(css) 使用css选择器从document中查询指定元素 ,返回Elements类型
- String title() 获取文档标题元素的字符串内容。
- Element head() 文档头元素的访问者
- Element body() 文档主体元素的访问者。
Elements:
- Elements select(String query) 在此元素列表中查找匹配的元素。
- Element get(int index) 返回此列表中指定位置的元素
- String text() 获取元素的value
- boolean hasText() 判断是否有内容
- List<String> eachText() 获取每个匹配元素的文本内容
- String html() 获取所有匹配元素的组合内部HTML
- boolean is(String query) 测试是否有匹配的元素如果有则为true。
- Elements next() 获取此列表中每个元素的下一个同级元素
- Elements next(String query) 获取此列表中每个元素的下一个同级元素,并通过查询进行筛选。
- Elements nextAll() 获取此列表中每个元素的以下所有元素同级。
- Elements nextAll(String query) 获取此列表中每个元素的以下所有元素同级,并通过查询进行筛选。
- Elements prev() 获取此列表中每个元素的前一个元素同级。
- Elements prev(String query) 获取此列表中每个元素的前一个元素同级,并通过查询进行筛选。
- Elements prevAll() 获取此列表中每个元素之前的所有同级元素。
- Elements prevAll(String query) 获取此列表中每个元素之前的所有同级元素,并通过查询进行筛选。
- Elements parents() 获取匹配元素的所有父元素和祖先元素。
- Element first() 获取第一个匹配的元素。
- Element last() 获取最后匹配的元素
- List<FormElement> forms() 从所选元素(如果有)中获取FormElement表单
- Elements filter(NodeFilter nodeFilter) 对每个选定元素执行深度优先过滤 (可以控制具体怎么遍历)
- Elements traverse(NodeVisitor nodeVisitor) 对每个选定元素执行深度优先遍历 (一直遍历到结束)
Element:
- Elements parents() 获取此元素的父元素和祖先元素,直到文档根。
- Element parent() 获取父元素
- String tagName() 获取此元素的标记名称
- boolean isBlock() 测试此元素是否为块级元素
- String id() 获取此元素的id属性。
- Attributes attributes() 获取元素上所有属性
- Element child(int index) 通过该元素的基于0的索引号获取该元素的子元素。
- Elements children() 获取此元素的子元素列表
- List<TextNode> textNodes() 获取此元素的子文本节点
- Elements select(String cssQuery) 查找与选择器CSS查询匹配的元素
- Element selectFirst(String cssQuery) 查找与选择器CSS查询匹配的第一个元素
- boolean is(String cssQuery) 检查此元素是否与给定的选择器CSS查询匹配。
- Element nextElementSibling() 获取此元素的下一个同级元素
- Elements siblingElements() 获取兄弟元素。如果元素没有同级元素 则返回空列表
- String cssSelector() 获取将唯一选择此元素的CSS选择器。(可用于检索选择器中元素的CSS路径)
- Element previousElementSibling() 获取此元素的上一个同级元素
- Element firstElementSibling() 获取此元素的第一个同级元素
- int elementSiblingIndex() 在其元素同级列表中获取此元素的列表索引。 如果这是第一个同级元素,则返回0。
- Element lastElementSibling() 获取此元素的最后一个同级元素
- Elements getElementsByTag(String tagName) 查找具有指定标签名的元素,包括此元素下的元素并递归查找。
- Element getElementById(String id) 按ID查找元素,包括或在此元素下
- Elements getElementsByClass(String className) 查找具有此类的元素,包括或在该元素下。不区分大小写
- Elements getElementsByAttribute(String key) 查找具有命名属性集的元素。不区分大小写。
- Elements getElementsByAttributeStarting(String keyPrefix) 查找属性名称以提供的前缀开头的元素。
- Elements getElementsByAttributeValue(String key, String value) 查找具有具有特定值的属性的元素。不区分大小写。
- Elements getElementsByAttributeValueNot(String key, String value) 查找没有此属性=值的元素。不区分大小写。
- Elements getElementsByAttributeValueStarting(String key, String valuePrefix) 查找属性以值前缀开头的元素。不区分大小写。
- Elements getElementsByAttributeValueEnding(String key, String valueSuffix) 查找属性以值后缀结尾的元素。不区分大小写。
- Elements getElementsByAttributeValueContaining(String key, String match) 查找具有其值包含匹配字符串的属性的元素。不区分大小写。
- Elements getElementsByAttributeValueMatching(String key, Pattern pattern) 查找具有值与提供的正则表达式匹配的属性的元素。
- Elements getElementsByAttributeValueMatching(String key, String regex) 查找具有值与提供的正则表达式匹配的属性的元素。
- Elements getElementsByIndexLessThan(int index) 查找同级索引小于提供的索引的元素。
- Elements getElementsByIndexGreaterThan(int index) 查找同级索引大于提供的索引的元素。
- Elements getElementsByIndexEquals(int index) 查找同级索引等于提供的索引的元素
- Elements getElementsContainingText(String searchText) 查找包含指定字符串的元素。文本可以直接出现在元素中,也可以出现在其任何子元素中。(在元素的文本中查找)
- Elements getElementsContainingOwnText(String searchText) 查找直接包含指定字符串的元素。搜索不区分大小写。文本必须直接出现在元素中,而不是其任何子体中 (在元素自己的文本中查找)
- Elements getElementsMatchingText(Pattern pattern) 查找其文本与提供的正则表达式匹配的元素
- Elements getElementsMatchingText(String regex) 查找其文本与提供的正则表达式匹配的元素
- Elements getElementsMatchingOwnText(Pattern pattern) 查找其自身文本与提供的正则表达式匹配的元素。
- Elements getElementsMatchingOwnText(String regex) 查找其自身文本与提供的正则表达式匹配的元素。
- Elements getAllElements() 查找此元素下的所有元素(包括self和children的子元素)
- String text() 获取此元素及其所有子元素的组合文本。空白被规范化和修剪。
- String wholeText() 获取该元素所有子元素的(未编码)文本,包括原始元素中存在的任何换行符和空格。
- String ownText() 获取仅由该元素拥有的文本;无法获取所有子级的组合文本。
- boolean hasText() 测试这个元素是否有任何文本内容(不仅仅是空白)。 如果元素具有非空白文本内容,则为true。
- String data() 获取此元素的组合数据。例如,数据是脚本标记的内部。请注意,数据不是元素的文本。使用text()获取用户可见的文本,使用data()获取脚本、注释、CSS样式等的内容。
- String className() 获取此元素的“class”属性的文字值,该属性可能包括多个类名,用空格分隔。
- Set<String> classNames() 获取所有元素的类名
- boolean hasClass(String className) 测试此元素是否具有类。不区分大小写
- String val() 获取表单元素的值(input、textarea等)。
使用JSOUP 方式连接
高并发爬取使用OkHttp,因为内部做了很多的优化,在爬取的频率很快和多的时候效率是非常好的, JSOUP内部提供了请求方式但效率没有OkHttp高,下面是封装好的直接就可以用,但是只支持返回xml/html页面否则报错,所以尽量使用OkHttp比较灵活,效率还好
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
/**
* 简要描述
* @Author: huanmin
* @Date: 2022/7/17 18:47
* @Version: 1.0
* @Description: 文件作用详细描述....
* Document execute = JsoupConnect.build("http://www.weather.com.cn/textFC/hb.shtml").getExecute();
*/
public class JsoupConnect {
private final Connection connect;
public static JsoupConnect build(String url) {
return new JsoupConnect(url);
}
public Document getExecute() {
Document document = null;
try {
document = connect.get();
} catch (IOException e) {
e.printStackTrace();
}
return document;
}
public Document postExecute() {
Document document = null;
try {
document = connect.get();
} catch (IOException e) {
e.printStackTrace();
}
return document;
}
public JsoupConnect(String url) {
Connection connect1 = Jsoup.connect(url);
TrustManager[] trustManagers = buildTrustManagers();
connect1.timeout(30000);//超时时间 30秒
connect1.sslSocketFactory(createSSLSocketFactory(trustManagers));
connect1.userAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
this.connect =connect1;
}
//设置代理
// Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8080));
public JsoupConnect proxy(Proxy.Type type,String ip,int port) {
Proxy proxy = new Proxy(type, new InetSocketAddress(ip, port));
this.connect.proxy(proxy);
return this;
}
public JsoupConnect cookie(String name, String value){
connect.cookie(name,value);
return this;
}
public JsoupConnect header(String name, String value){
connect.header(name,value);
return this;
}
//get 和 post
public JsoupConnect addParameter(String key, String value){
connect.data(key,value);
return this;
}
/**
* 生成安全套接字工厂,用于https请求的证书跳过
*
* @return
*/
private SSLSocketFactory createSSLSocketFactory(TrustManager[] trustAllCerts) {
SSLSocketFactory ssfFactory = null;
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
ssfFactory = sc.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
return ssfFactory;
}
private TrustManager[] buildTrustManagers() {
return new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
};
}
}
User-Agent(随机)
User-Agent是Http协议中的一部分,属于头域的组成部分,User Agent也简称UA。用较为普通的一点来说,是一种向访问网站提供你所使用的浏览器类型、操作系统及版本、CPU 类型、浏览器渲染引擎、浏览器语言、浏览器插件等信息的标识。UA字符串在每次浏览器 HTTP 请求时发送到服务器! ,所以大批量爬虫的时候不要一直使用同一个User-Agent, 要多切换切换,不然就会识别到你了给你拉黑
可以利用随机的方式来获取下面的内容
Mozilla/5.0 (Windows; U; Windows NT 10.0) AppleWebKit/535.11.3 (KHTML, like Gecko) Version/4.0 Safari/535.11.3
Mozilla/5.0 (compatible; MSIE 5.0; Windows NT 6.0; Trident/3.1)
Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 6.1; Trident/4.0)
Mozilla/5.0 (Windows; U; Windows 98) AppleWebKit/534.49.4 (KHTML, like Gecko) Version/4.0.3 Safari/534.49.4
Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 10.0; Trident/3.1)
Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/3.1)
Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/24.0.860.0 Safari/535.2
Mozilla/5.0 (Windows CE; mt-MT; rv:1.9.2.20) Gecko/2013-04-30 01:12:55 Firefox/3.8
Mozilla/5.0 (Windows; U; Windows CE) AppleWebKit/533.14.1 (KHTML, like Gecko) Version/5.0.1 Safari/533.14.1
Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 5.01; Trident/5.0)
Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 6.2; Trident/4.1)
Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 10.0; Trident/5.1)
Mozilla/5.0 (Windows NT 5.2; kok-IN; rv:1.9.2.20) Gecko/2011-09-17 16:05:22 Firefox/3.8
Opera/9.36.(Windows NT 6.1; gd-GB) Presto/2.9.178 Version/11.00
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/3.0)
Mozilla/5.0 (Windows NT 6.1; tl-PH; rv:1.9.1.20) Gecko/2017-02-01 17:55:13 Firefox/3.6.14
Mozilla/5.0 (compatible; MSIE 6.0; Windows 98; Trident/5.0)
Mozilla/5.0 (compatible; MSIE 7.0; Windows CE; Trident/3.1)
Mozilla/5.0 (Windows; U; Windows NT 6.1) AppleWebKit/535.41.7 (KHTML, like Gecko) Version/5.0.1 Safari/535.41.7
Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 6.2; Trident/3.0)
Mozilla/5.0 (Windows NT 6.2) AppleWebKit/533.0 (KHTML, like Gecko) Chrome/57.0.812.0 Safari/533.0
Opera/9.85.(Windows NT 5.2; kk-KZ) Presto/2.9.172 Version/12.00
Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.2; Trident/3.1)
Mozilla/5.0 (Windows; U; Windows 95) AppleWebKit/535.8.1 (KHTML, like Gecko) Version/4.0.1 Safari/535.8.1
Opera/9.39.(Windows 98; Win 9x 4.90; cmn-TW) Presto/2.9.189 Version/10.00
Mozilla/5.0 (Windows NT 4.0) AppleWebKit/531.2 (KHTML, like Gecko) Chrome/14.0.876.0 Safari/531.2
Mozilla/5.0 (Windows; U; Windows NT 4.0) AppleWebKit/531.4.5 (KHTML, like Gecko) Version/5.0.3 Safari/531.4.5
Opera/9.18.(Windows 98; Win 9x 4.90; aa-ER) Presto/2.9.166 Version/12.00
Mozilla/5.0 (Windows 95; ml-IN; rv:1.9.2.20) Gecko/2018-05-02 05:15:13 Firefox/3.8
Opera/9.52.(Windows NT 5.1; mhr-RU) Presto/2.9.160 Version/10.00
Mozilla/5.0 (compatible; MSIE 8.0; Windows CE; Trident/5.0)
Mozilla/5.0 (Windows NT 5.1; nan-TW; rv:1.9.1.20) Gecko/2020-02-12 23:57:29 Firefox/6.0
Mozilla/5.0 (Windows NT 4.0; cv-RU; rv:1.9.1.20) Gecko/2016-08-13 23:30:24 Firefox/3.8
Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 4.0; Trident/5.1)
Opera/9.34.(Windows NT 6.1; szl-PL) Presto/2.9.182 Version/12.00
Mozilla/5.0 (compatible; MSIE 7.0; Windows 98; Win 9x 4.90; Trident/4.0)
Opera/8.35.(Windows NT 5.0; az-AZ) Presto/2.9.171 Version/12.00
Opera/9.85.(Windows 98; sr-RS) Presto/2.9.167 Version/10.00
Mozilla/5.0 (Windows NT 5.1; ru-UA; rv:1.9.0.20) Gecko/2011-12-14 02:08:36 Firefox/3.8
Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/3.0)
Mozilla/5.0 (Windows NT 4.0) AppleWebKit/536.2 (KHTML, like Gecko) Chrome/28.0.862.0 Safari/536.2
Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 6.0; Trident/5.1)
Opera/9.50.(Windows NT 5.0; mk-MK) Presto/2.9.161 Version/11.00
Mozilla/5.0 (compatible; MSIE 5.0; Windows NT 6.0; Trident/5.1)
Opera/8.41.(Windows NT 5.01; az-IN) Presto/2.9.177 Version/11.00
Mozilla/5.0 (compatible; MSIE 8.0; Windows 98; Trident/3.0)
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 4.0; Trident/4.1)
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.2; Trident/4.0)
Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.2; Trident/4.1)
Mozilla/5.0 (Windows; U; Windows 98) AppleWebKit/531.36.3 (KHTML, like Gecko) Version/4.0.3 Safari/531.36.3
Mozilla/5.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Trident/4.0)
Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)
Mozilla/5.0 (compatible; MSIE 8.0; Windows 98; Trident/4.1)
Mozilla/5.0 (Windows NT 4.0) AppleWebKit/536.2 (KHTML, like Gecko) Chrome/39.0.826.0 Safari/536.2
Mozilla/5.0 (Windows; U; Windows CE) AppleWebKit/533.1.3 (KHTML, like Gecko) Version/4.0.2 Safari/533.1.3
Mozilla/5.0 (compatible; MSIE 5.0; Windows NT 5.1; Trident/5.1)
Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.2; Trident/5.1)
Mozilla/5.0 (Windows; U; Windows 95) AppleWebKit/531.4.2 (KHTML, like Gecko) Version/5.1 Safari/531.4.2
Mozilla/5.0 (Windows NT 5.01; tr-CY; rv:1.9.2.20) Gecko/2013-09-06 07:39:53 Firefox/9.0
Mozilla/5.0 (Windows; U; Windows NT 4.0) AppleWebKit/535.22.1 (KHTML, like Gecko) Version/5.0 Safari/535.22.1
Mozilla/5.0 (Windows; U; Windows NT 5.0) AppleWebKit/535.37.3 (KHTML, like Gecko) Version/4.1 Safari/535.37.3
Opera/8.64.(Windows NT 5.1; yue-HK) Presto/2.9.182 Version/10.00
Opera/8.27.(Windows NT 6.1; bo-CN) Presto/2.9.180 Version/12.00
Opera/9.82.(Windows NT 5.01; lij-IT) Presto/2.9.185 Version/12.00
Opera/8.12.(Windows CE; ne-NP) Presto/2.9.160 Version/12.00
Opera/8.55.(Windows NT 5.1; it-CH) Presto/2.9.171 Version/10.00
Mozilla/5.0 (Windows; U; Windows NT 5.0) AppleWebKit/532.45.4 (KHTML, like Gecko) Version/4.0.2 Safari/532.45.4
Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/4.0)
Mozilla/5.0 (Windows; U; Windows 98; Win 9x 4.90) AppleWebKit/532.32.3 (KHTML, like Gecko) Version/4.0 Safari/532.32.3
Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.0; Trident/5.1)
Opera/9.26.(Windows CE; af-ZA) Presto/2.9.172 Version/10.00
Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 6.1; Trident/5.1)
Mozilla/5.0 (compatible; MSIE 7.0; Windows 98; Win 9x 4.90; Trident/5.0)
Mozilla/5.0 (Windows NT 5.1; or-IN; rv:1.9.0.20) Gecko/2012-05-22 18:16:14 Firefox/3.8
Mozilla/5.0 (Windows; U; Windows NT 6.2) AppleWebKit/533.29.5 (KHTML, like Gecko) Version/5.0.5 Safari/533.29.5
Opera/9.93.(Windows 98; ka-GE) Presto/2.9.184 Version/12.00
Mozilla/5.0 (Windows NT 5.1) AppleWebKit/531.2 (KHTML, like Gecko) Chrome/29.0.812.0 Safari/531.2
Mozilla/5.0 (Windows; U; Windows CE) AppleWebKit/533.43.7 (KHTML, like Gecko) Version/5.1 Safari/533.43.7
Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 5.2; Trident/5.1)
Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.2; Trident/3.0)
Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/3.1)
Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.01; Trident/5.0)
Opera/9.75.(Windows NT 5.01; as-IN) Presto/2.9.180 Version/11.00
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 5.0; Trident/3.1)
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0)
Mozilla/5.0 (Windows NT 5.0) AppleWebKit/536.2 (KHTML, like Gecko) Chrome/24.0.826.0 Safari/536.2
Mozilla/5.0 (Windows 95; nb-NO; rv:1.9.1.20) Gecko/2013-09-05 15:16:44 Firefox/11.0
Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.2 (KHTML, like Gecko) Chrome/52.0.861.0 Safari/536.2
Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 10.0; Trident/3.0)
Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.0; Trident/4.0)
Mozilla/5.0 (compatible; MSIE 5.0; Windows 98; Win 9x 4.90; Trident/3.0)
Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/3.0)
Mozilla/5.0 (Windows; U; Windows NT 6.2) AppleWebKit/533.35.5 (KHTML, like Gecko) Version/5.0 Safari/533.35.5
Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.1)
Mozilla/5.0 (Windows 98; Win 9x 4.90) AppleWebKit/532.2 (KHTML, like Gecko) Chrome/60.0.830.0 Safari/532.2
Opera/8.23.(Windows NT 5.2; byn-ER) Presto/2.9.189 Version/11.00
Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.0; Trident/5.1)
Opera/9.93.(Windows NT 5.1; az-AZ) Presto/2.9.173 Version/10.00
Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/52.0.845.0 Safari/535.1
Mozilla/5.0 (compatible; MSIE 8.0; Windows 95; Trident/3.1)
package com.reptile;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import com.google.common.io.Resources;
import java.io.File;
import java.net.URL;
import java.util.Collections;
import java.util.List;
/**
* 简要描述
*
* @Author: huanmin
* @Date: 2022/7/17 19:51
* @Version: 1.0
* @Description: 文件作用详细描述....
*/
public class UserAgent {
private static List<String> userAgentsWindows = null;
static {
URL url = Resources.getResource("userAgents_windows");
if(url != null) {
File file = new File(url.getPath());
try {
userAgentsWindows = Files.readLines(file, Charsets.UTF_8);
} catch(Exception ex) {}
}
}
public static String getUserAgentWindows() {
if(userAgentsWindows == null || userAgentsWindows.size() == 0) {
return "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36";
}
Collections.shuffle(userAgentsWindows);
return userAgentsWindows.get(0);
}
}
后台爬虫的三大问题
后台爬虫在大行其道的时候,也有着些许棘手的、到目前也没有什么好的解决方案问题,而归根结底,这些问题的根本原因是由于后台爬虫的先天不足导致,在正式讨论之前,我们先思考一个问题,“爬虫和浏览器有什么异同?”
相同点: 本质上都是通过http/https协议请求互联网数据
不同点:
- 爬虫一般为自动化程序,无需用用户交互,而浏览器不是
- 运行场景不同 ,浏览器运行在客户端,而爬虫一般都跑在服务端
- 能力不同, 浏览器包含渲染引擎、javascript ,而爬虫一般都不具备这两者。
了解了这些,我们再来看看后台面临的问题
问题一:交互问题
有些网页往往需要和用户进行一些交互,进而才能走到下一步,比如输入一个验证码,拖动一个滑块,选几个汉字。网站之所以这么做,很多时候都是为了验证访问者到底是人还是机器。
而爬虫程序遇到这种情况很难处理,传统的简单图片验证码可以通过图形处理算法读出内容,但是随着各种各样,花样百出,人神共愤的、变态的验证码越来越多(尤其是买火车票时,分分钟都想爆粗口),这个问题就越来越严重。
问题二:Javascript 解析问题
如前文所述,javascript可以动态生成dom。目前大多数网页属于动态网页内容由javascript动态填充,尤其是在移动端,SPA/PWA应用越来越流行,网页中大多数有用的数据都是通过ajax/fetch动态获取后然后再由js填充到网页dom树中,单纯的html静态页面中有用的数据很少。
目前主要应对的方案就是对于js ajax/fetch请求直接请求ajax/fetch的url ,但是还有一些ajax的请求参数会依赖一段javascript动态生成,比如一个请求签名,再比如用户登陆时对密码的加密等等。
如果一昧的去用后台脚本去干javascript本来做的事,这就要清楚的理解原网页代码逻辑,而这不仅非常麻烦,而且会使你的爬取代码异常庞大臃肿,但是,更致命的是,有些javascript可以做的事爬虫程序是很难甚至是不能模仿的,比如有些网站使用拖动滑块到某个位置的验证码机制,这就很难再爬虫中去模仿。
其实,总结一些,这些弊端归根结底,是因为爬虫程序并非是浏览器,没有javascript解析引擎所致。针对这个问题,目前主要的应对策略就是直接以真实用户的角度去爬取,比如Java-Selenium自动化 ,但是又有着明显的弊端,如服务器同时有多个爬取任务时,资源占用太大。
还有就是,这些 无窗口的javascript引擎很多时候使用起来并不能像在浏览器环境中一样,页面内部发生跳转时,会导致流程很难控制。
问题三:IP限制
这是目前对后台爬虫中最致命的。网站的防火墙会对某个固定ip在某段时间内请求的次数做限制,如果没有超过上线则正常返回数据,超过了,则拒绝请求,如qq 邮箱。
值得说明的是,ip限制有时并非是专门为了针对爬虫的,而大多数时候是出于网站安全原因针对DOS攻击的防御措施。后台爬取时机器和ip有限,很容易达到上线而导致请求被拒绝。目前主要的应对方案是使用代理,这样一来ip的数量就会多一些,但代理ip需要花钱
后记
采用爬虫或者自动化处理业务,如果是静态网页还比较好处理,如果是AJAX+JS渲染的动态页面,在爬取的过程中,会遇到各种各样的坑,就需要耐心研究了到底怎么才能获取到, 有些时候我们还需要通过自动化来跳过验证等…