内容包含:
1,简略描述爬虫代码编写流程
2,对于动态页面的爬取
代码:
https://github.com/zackLangChina/JavaCrawler
一,爬虫代码编写流程
1.1,发送HTTP request,获取HTTP response
java:
//使用OKHTTP发送request
private static OkHttpClient client = new OkHttpClient();
//返回html
public static String get(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
python:
import requests
#返回HTTP
def getHTTPText(url):
try:
r = requests.get(url, timeout=10)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""
1.2,在HTTP源码中搜索我们需要的元素
CSS选择器、正则表达式匹配等方式查找
java:
//JSOUP解析
Document document = Jsoup.parse(mHtml);
Elements elements = document
.select("ul[class=feed-list-hits feed-list-index]")
.select("li[class=feed-row-wide J_feed_za feed-haojia]");
for (Element element : elements) {
...
python:
//BeautifulSoup解析
soup = BeautifulSoup(html, "html.parser")
for li in soup.find_all(name="li", attrs={"class": "av-gallery-item"}):
1.3,数据本地存储
写CSV文件或写数据库
当然,实际应用中会遇见很多问题:
1,需要模拟按键等操作
2,需要获取异步数据XHR并解析
3,反爬机制
二,静态页面和Ajax页面
某一网址为 https://www.xxx.com/xxx?id=a&page=b&value=c 这样的网址,显性地将属性添加到主体的后面,那么对于这类网站,我们只需要修改request的url就能抓取到静态页面中的数据。
对于Ajax的网页,网页刷新时,浏览器的Url并不会改变,而是通过发送一个request,获取了页面上一部分数据的刷新。ajax请求可能获得的是一部分页面的html代码,也可能是json格式的表单数据,我们可以在F12的preview或response里查看具体获得的数据类型,做不同的处理。
2.1构建ajax页面的request
以企查查举例。进入某个公司信息的页面,查看知识产权-专利信息,我们点击专利信息的翻页按钮,浏览器地址栏的url是不变的。打开F12,查看XHR信息,可以在Headers中看到request和response:
XHR
同时,在XHR的Response中可以看到新打开页面的HTML代码:
ajax返回的页面代码
我们还可以在Headers的最下面看到我们点击翻页时,request中带了哪些信息:
请求时发送的信息
这个图里我们可以看出,request带的主要信息有:
unique / companyname / p / tab / box
还有一些空参数:zlpublicationyear / zlipclist / zlkindcode / zllegalstatus
对比了两个公司的XHR Headers:
公司A:
https://www.qcc.com/company_getinfos?unique=06396efe66551d4ac07ee8cb41b0e325&companyname=%E5%B9%BF%E4%B8%9C%E5%B9%BF%E4%BF%A1%E9%80%9A%E4%BF%A1%E6%9C%8D%E5%8A%A1%E6%9C%89%E9%99%90%E5%85%AC%E5%8F%B8&p=2&tab=assets&box=zhuanli&zlpublicationyear=&zlipclist=&zlkindcode=&zllegalstatus=
公司B:
https://www.qcc.com/company_getinfos?unique=70991e4c3796c47dd9d9e634fec5def0&companyname=%E6%B5%99%E6%B1%9F%E5%8D%8E%E4%BB%AA%E7%94%B5%E5%AD%90%E8%82%A1%E4%BB%BD%E6%9C%89%E9%99%90%E5%85%AC%E5%8F%B8&p=2&tab=assets&box=zhuanli&zlpublicationyear=&zlipclist=&zlkindcode=&zllegalstatus=
可以通过参数的差异和页面信息分析出参数的含义:
unique:企查查中某个公司的主页地址。如打开某个公司,地址栏是:
https://www.qcc.com/firm_06396efe66551d4ac07ee8cb41b0e325.html
06396efe66551d4ac07ee8cb41b0e325就和上面的unique=06396efe66551d4ac07ee8cb41b0e325值对应上了
companyname:公司名称
p:网页的页数,于是只要更改该键的值,我们就可以实现对每一页进行爬取
tab:标签页,代表了知识产权页面
box:作为不同的表格的标识。这里的zhuanli特指专利信息表格
那么,我们就可以给出爬取企查查企业专利信息的代码流程了:
1,获取企业名称列表
2,进入企业页面
3,从静态页面中获取专利信息总共的页数,如下图,可以通过遍历div class="m-b"中的元素得知总共有多少页
4,构建request,获取response中的页面信息
步骤3,获取专利信息页码
用代码说明一些细节:
private final String url = "https://www.qcc.com/company_getinfos";
private final String KEY_UNIQUE = "unique";
private final String KEY_COMPANY = "companyname";
private final String KEY_P = "p";
private final String KEY_TAB = "tab";
private final String KEY_BOX = "box";
private final String TAB_ASSERTS = "assets";
private final String BOX_ZHUANLI = "zhuanli";
private final String COOKIE = "xxx" //浏览器的cookie,QCC不登录不能查询
//通过HttpUrl.Builder构建参数键值对,其实就是帮你拼接字符串
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
urlBuilder.addQueryParameter(KEY_UNIQUE,"06396efe66551d4ac07ee8cb41b0e325");
urlBuilder.addQueryParameter(KEY_COMPANY,"广东广信通信服务有限公司");
urlBuilder.addQueryParameter(KEY_P,"1");
urlBuilder.addQueryParameter(KEY_TAB,TAB_ASSERTS);
urlBuilder.addQueryParameter(KEY_BOX,BOX_ZHUANLI);
//发送请求,注意需要补充请求头
Request request = new Request.Builder()
.url(urlBuilder.build())
.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36")
.addHeader("Cookie", cookie)
.addHeader("accept","text/html, */*; q=0.01")
.addHeader("accept-encoding","gzip, deflate, br")
.addHeader("accept-language","zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7")
.addHeader("referer","https://www.qcc.com/firm_06396efe66551d4ac07ee8cb41b0e325.html")
.addHeader("sec-fetch-dest","empty")
.addHeader("sec-fetch-mode","cors")
.addHeader("sec-fetch-site","same-origin")
.addHeader("x-requested-with","XMLHttpRequest")
.build();
Response response = client.newCall(request).execute();
//返回html
return response.body().string();
如果不把header加全一些,会被禁止访问:
企查查反爬
但即便这样,reponse得到的是一堆乱码,不知道具体是什么。但至少说明这样是可以用来获取ajax动态网页数据的,达到了学习的目的。
response返回
网友评论