java爬虫抓取动态网页(实战|*敏*感*词*教你用Python爬虫(附详细源码)(图))
优采云 发布时间: 2021-12-01 18:10java爬虫抓取动态网页(实战|*敏*感*词*教你用Python爬虫(附详细源码)(图))
项目背景
事情是这样的。前几天,我的公众号写了一篇实战爬虫入口文章,名为《实战|教你使用Python爬虫(附详细源码)》。发出后不到一天,一位从业10年的王*敏*感*词*找上我。虽然同意了他的微信申请,但心里还是有些慌。
点击此处获取海量Python学习资料!
短暂交流后,原来他是在自学爬虫,结果翻页发现网址没变。其实他爬取的网页难度比较大,也就是这次要详细介绍的动态网页。一向乐于助人的J哥,自然会在最短的时间内给他指明方向,从青铜到白银。
AJAX 动态加载网页
一
什么是动态网页
J哥一向注重理论与实践的结合,知其然也必知其所以然,才能应付一切变化而无变化。
所谓动态网页,是指一种与静态网页相对的网页编程技术。对于静态网页,随着html代码的生成,页面的内容和显示效果基本不会发生变化——除非你修改页面代码。这不是动态网页的情况。虽然页面代码没有改变,但显示的内容会随着时间、环境或数据库操作的结果而改变。——来源百度百科
动态网页具有工作量少、内容更新快、功能更齐全的特点。被很多公司采用,如购动、速食宝、速食等。
二
什么是 AJAX
随着人们对动态网页的加载速度要求越来越高,AJAX 技术应运而生,成为许多网站的首选。AJAX 是一种用于创建快速动态网页的技术,通过在后台与服务器进行少量数据交换,使网页可以异步更新。这意味着可以在不重新加载整个网页的情况下更新网页的某些部分。
三
如何抓取AJAX动态加载的网页
1. 分析界面
只要有数据发送,就一定有请求发送到服务器。我们只需要找出它静默加载的页面的真实请求。特点:爬取速度快,爬取数据干净,部分网站比较难解析。
2. 硒
什么是硒?它最初是一个自动化测试工具,但它被广泛的用户抓取。是一个可以用代码操作浏览器的工具,比如控制浏览器的下滑,模拟鼠标点击等。 特点:代码比较简单,爬取速度慢,IP容易被封。
项目实践
理论这么多,老实说,J哥也不想这么啰嗦。但是,这些东西经常被问到,所以把它们写下来。下次有人问,就送他这个文章,一劳永逸!
好,让我们回到王*敏*感*词*的部分。作为资深*敏*感*词*,王*敏*感*词*深知,研究*敏*感*词*多年来公开的开庭信息和执行信息,对于提升业务能力具有重要作用。于是他兴高采烈地打开了法庭信息公开网页。
它看起来像这样:
然后,他按照J哥之前写的爬虫介绍文章抓取数据,成功提取到第一页。他异常兴奋。
紧接着,他又加了一个for循环,想着花几分钟把这个网站2164页共32457条宣判数据提取到excel中。
然后,就没有了。你也应该知道,看了前面的理论部分,这是一个AJAX动态加载的网页。无论你如何点击下一页,url都不会改变。如果你不相信我,我就给你看。左上角的url像山一样矗立在那里:
一
解析接口
既然如此,那我们就开始爬虫的正确姿势,先用解析接口的方法来写爬虫。
首先,找到真正的请求。右键勾选,点击Network,选择XHR,刷新网页,在Name列表中选择jsp文件。没错,就是这么简单,真正的要求就藏在里面。
再仔细看看这个jsp,这简直就是宝藏。有真实的请求url、post请求方法、Headers、Form Data,From Data代表传递给url的参数。通过改变参数,我们可以得到数据!为了安全起见,我为我的 Cookie 做了马赛克。机智的朋友可能已经发现我顺便给自己打了广告。
让我们仔细看看这些参数, pagesnum 参数不仅仅代表页数!王*敏*感*词*顿时恍然大悟,原来他思考的那一页,竟然翻到了这里!穿越千山万水,终于找到了你!我们尝试点击翻页,发现只有 pagesnum 参数会发生变化。
既然找到了,赶紧抓起来吧。J哥以闪电般的速度打开了PyCharm,导入了爬虫需要的库。
1from urllib.parse import urlencode
2import csv
3import random
4import requests
5import traceback
6from time import sleep
7from lxml import etree #lxml为第三方网页解析库,强大且速度快
构造一个真正的请求并添加标题。J哥没有把他的User-Agent和Cookie贴在这里,主要是一向胆小的J哥被吓到了。
1base_url = 'http://www.hshfy.sh.cn/shfy/gweb2017/ktgg_search_content.jsp?' #这里要换成对应Ajax请求中的链接
2
3headers = {
4 'Connection': 'keep-alive',
5 'Accept': '*/*',
6 'X-Requested-With': 'XMLHttpRequest',
7 'User-Agent': '你的User-Agent',
8 'Origin': 'http://www.hshfy.sh.cn',
9 'Referer': 'http://www.hshfy.sh.cn/shfy/gweb2017/ktgg_search.jsp?zd=splc',
10 'Accept-Language': 'zh-CN,zh;q=0.9',
11 'Content-Type': 'application/x-www-form-urlencoded',
12 'Cookie': '你的Cookie'
13}
构造get_page函数,参数为page,即页数。创建字典类型的表单数据,并使用post请求网页数据。这里一定要注意对返回数据的解码,编码为'gbk',否则返回数据会出现乱码!另外,我还优化了异常处理,防止意外。
1def get_page(page):
2 n = 3
3 while True:
4 try:
5 sleep(random.uniform(1, 2)) # 随机出现1-2之间的数,包含小数
6 data = {
7 'yzm': 'yxAH',
8 'ft':'',
9 'ktrqks': '2020-05-22',
10 'ktrqjs': '2020-06-22',
11 'spc':'',
12 'yg':'',
13 'bg':'',
14 'ah':'',
15 'pagesnum': page
16 }
17 url = base_url + urlencode(data)
18 print(url)
19 try:
20 response = requests.request("POST",url, headers = headers)
21 #print(response)
22 if response.status_code == 200:
23 re = response.content.decode('gbk')
24 # print(re)
25 return re # 解析内容
26 except requests.ConnectionError as e:
27 print('Error', e.args) # 输出异常信息
28 except (TimeoutError, Exception):
29 n -= 1
30 if n == 0:
31 print('请求3次均失败,放弃此url请求,检查请求条件')
32 return
33 else:
34 print('请求失败,重新请求')
35 continue
构造parse_page函数解析返回的网页数据,用Xpath提取所有字段内容,并保存为csv格式。有人会问为什么J哥那么喜欢用Xpath,因为它简单好用!!!这么简单的网页结构,我做不了普通的大法安装。J兄弟,我做不到。
1def parse_page(html):
2 try:
3 parse = etree.HTML(html) # 解析网页
4 items = parse.xpath('//*[@id="report"]/tbody/tr')
5 for item in items[1:]:
6 item = {
7 'a': ''.join(item.xpath('./td[1]/font/text()')).strip(),
8 'b': ''.join(item.xpath('./td[2]/font/text()')).strip(),
9 'c': ''.join(item.xpath('./td[3]/text()')).strip(),
10 'd': ''.join(item.xpath('./td[4]/text()')).strip(),
11 'e': ''.join(item.xpath('./td[5]/text()')).strip(),
12 'f': ''.join(item.xpath('./td[6]/div/text()')).strip(),
13 'g': ''.join(item.xpath('./td[7]/div/text()')).strip(),
14 'h': ''.join(item.xpath('./td[8]/text()')).strip(),
15 'i': ''.join(item.xpath('./td[9]/text()')).strip()
16 }
17 #print(item)
18 try:
19 with open('./law.csv', 'a', encoding='utf_8_sig', newline='') as fp:
20 # 'a'为追加模式(添加)
21 # utf_8_sig格式导出csv不乱码
22 fieldnames = ['a', 'b', 'c', 'd', 'e','f','g','h','i']
23 writer = csv.DictWriter(fp,fieldnames)
24 writer.writerow(item)
25 except Exception:
26 print(traceback.print_exc()) #代替print e 来输出详细的异常信息
27 except Exception:
28 print(traceback.print_exc())
最后遍历页数,调用函数。OK完成!
1 for page in range(1,5): #这里设置想要爬取的页数
2 html = get_page(page)
3 #print(html)
4 print("第" + str(page) + "页提取完成")
我们来看看最终的效果:
二
硒
渴望学习的朋友可能还想看看Selenium是如何爬取AJAX动态加载的网页的。J哥自然会满足你的好奇心。于是赶紧新建了一个py文件,准备趁势而上,用Selenium把这个网站爬下来。
首先,导入相关库。
1from lxml import etree
2import time
3from selenium import webdriver
4from selenium. webdriver.support.wait import WebDriverWait
5from selenium.webdriver.support import expected_conditions as EC
6from selenium.webdriver.common.by import By
然后,使用chromedriver驱动打开这个网站。
1def main():
2 # 爬取首页url
3 url = "http://www.hshfy.sh.cn/shfy/gweb2017/flws_list.jsp?ajlb=aYWpsYj3D8crCz"
4 # 定义谷歌webdriver
5 driver = webdriver.Chrome('./chromedriver')
6 driver.maximize_window() # 将浏览器最大化
7 driver.get(url)
所以,我惊讶地发现报告了一个错误。以CET-6英语的词汇储备,J哥居然听懂了!可能是我的驱动和浏览器版本不匹配,只支持79版本的浏览器。
J兄很郁闷,因为我以前用Selenium从来没有遇到过这种问题。J哥不甘心,打开谷歌浏览器查看版本号。
我失去了它!都更新到了81版!遇到这种情况,请好奇的朋友等待J哥设置浏览器自动更新并重新下载最新驱动,下次再来听听Selenium爬虫吧。记得关注本公众号,不要错过精彩哦~
综上所述,对于网络爬虫的AJAX动态加载,一般有两种方式:解析接口;硒。J兄推荐解析接口的方式。如果是解析json数据,最好是爬取。如果你不知道如何使用Selenium,让我们使用Selenium。