python抓取动态网页(动态加载网页一什么是动态网页(附详细源码))

优采云 发布时间: 2022-02-11 21:12

  python抓取动态网页(动态加载网页一什么是动态网页(附详细源码))

  用通俗易懂的语言分享爬虫、数据分析、可视化等干货,希望大家能学到新知识。

  项目背景

  事情是这样的,前几天,我的公众号写了一篇关于爬虫文章的介绍的文章,叫做《实战|教你如何使用Python爬虫(附详细源码)》。寄出后不到一天,一位从业10年的王*敏*感*词*找到了我。虽然我同意了他的微信申请,但我还是忍不住慌了。

  简单交流了一下,原来他是在自学爬虫,但是发现翻页的时候,url还是一样的。其实他爬的是比较难的网页,也就是这次要详细介绍的动态网页。一向乐于助人的J哥,自然会给他指点方向,在最短的时间内从青铜到白银。

  网页的AJAX动态加载

  一

  什么是动态网页

  J哥一直注重理论与实践的结合,一定要知道自己为什么会这样,才能应对一切变化而不作改变。

  所谓动态网页,是指相对于静态网页的一种网页编程技术。对于静态网页,随着html代码的生成,页面的内容和显示效果基本不会改变——除非你修改了页面代码。动态网页并非如此。虽然页面代码没有改变,但是显示的内容会随着时间、环境或数据库操作的结果而改变。——来源百度百科

  动态网页具有工作量减少、内容更新快、可以完成的功能多等特点。

  二

  什么是 AJAX

  随着人们对动态网页加载速度的要求越来越高,AJAX技术应运而生,成为众多网站的首选。AJAX 是一种用于创建快速和动态网页的技术,它通过在后台与服务器交换少量数据来实现网页的异步更新。这意味着可以在不重新加载整个网页的情况下更新网页的某些部分。

  三

  如何爬取 AJAX 动态加载的网页

  1. 解析接口

  只要有数据发送,就一定有请求发送到服务器。我们只需要找出它悄悄加载的页面的真实请求。特点:爬取速度快,爬取数据干净,部分网站难以解析。

  2. 硒

  什么是硒?它最初是一个自动化测试工具,但已经被广泛的用户爬取。是一个可以用代码操作浏览器的工具,比如控制浏览器的下滑,模拟鼠标点击等。特点:代码比较简单,爬取速度慢,ip容易被封.

  项目实践

  说了这么多理论,说实话,J哥不想这么啰嗦。不过这些东西经常被问到,干脆写下来,下次有人问,直接把这个文章发给他,一劳永逸!

  好,我们回到王*敏*感*词*的部分。作为一名资深*敏*感*词*,王*敏*感*词*深知,研究*敏*感*词*历年发布的*敏*感*词*信息和执行信息对于提升业务能力具有重要作用。于是,他兴高采烈地打开了法庭信息公示页面。

  它看起来像这样:

  然后,他按照J哥之前写的爬虫文章的介绍爬取了数据,成功提取了第一页,激动万分。

  紧接着,他加了一个for循环,想花几分钟把网站2164页的32457条法庭公告的数据提取到excel中。

  那么,就没有了。看完前面的理论部分,你也应该知道这是一个AJAX动态加载的网页。无论您如何点击下一页,网址都不会改变。不信,点进去给你看,左上角的url像山一样耸立在那里:

  一

  解析接口

  在这种情况下,让我们启动爬虫的正确姿势,首先使用解析接口的方法来编写爬虫。

  首先,找到真正的请求。右键查看,点击Network,选择XHR,刷新网页,在Name列表中选择jsp文件。是的,就是这么简单,真正的请求隐藏在里面。

  ‍

  让我们仔细看看这个jsp,简直是宝藏。有一个真实的请求url,一个请求方法post,Headers,和Form Data,From Data代表传递给url的参数。通过改变参数,我们可以得到数据!为了安全起见,我把我的饼干做了马赛克,机智的朋友可能已经注意到我顺便给自己做了一个广告。

  让我们仔细看看这些参数。pagesnum参数不代表页数!王*敏*感*词*顿悟了。原来,他在这里全心全意地翻开了这一页!穿越千山万水,终于找到了你!我们尝试点击翻页,发现只有pagesnum参数会改变。

  既然已经找到了,就赶紧抓起来吧。J哥以闪电般的速度打开PyCharm,导入爬虫所需的库。

  from urllib.parse import urlencode

import csv

import random

import requests

import traceback

from time import sleep

from lxml import etree #lxml为第三方网页解析库,强大且速度快

  构造一个真实的请求并添加Headers。J哥这里没有贴出自己的User-Agent和Cookie,主要是一向胆小的J哥怕了。

  base_url = 'http://www.hshfy.sh.cn/shfy/gweb2017/ktgg_search_content.jsp?' #这里要换成对应Ajax请求中的链接

headers = {

'Connection': 'keep-alive',

'Accept': '*/*',

'X-Requested-With': 'XMLHttpRequest',

'User-Agent': '你的User-Agent',

'Origin': 'http://www.hshfy.sh.cn',

'Referer': 'http://www.hshfy.sh.cn/shfy/gweb2017/ktgg_search.jsp?zd=splc',

'Accept-Language': 'zh-CN,zh;q=0.9',

'Content-Type': 'application/x-www-form-urlencoded',

'Cookie': '你的Cookie'

}

  构建get_page函数,参数为page,即页数。创建字典类型的表单数据,使用post方法请求网页数据。这里注意对返回的数据进行解码,编码为'gbk',否则返回的数据会乱码!此外,我还添加了异常处理优化,以防止意外发生。

  def get_page(page):

n = 3

while True:

try:

sleep(random.uniform(1, 2)) # 随机出现1-2之间的数,包含小数

data = {

'yzm': 'yxAH',

'ft':'',

'ktrqks': '2020-05-22',

'ktrqjs': '2020-06-22',

'spc':'',

'yg':'',

'bg':'',

'ah':'',

'pagesnum': page

}

url = base_url + urlencode(data)

print(url)

try:

response = requests.request("POST",url, headers = headers)

#print(response)

if response.status_code == 200:

re = response.content.decode('gbk')

# print(re)

return re # 解析内容

except requests.ConnectionError as e:

print('Error', e.args) # 输出异常信息

except (TimeoutError, Exception):

n -= 1

if n == 0:

print('请求3次均失败,放弃此url请求,检查请求条件')

return

else:

print('请求失败,重新请求')

continue

  构建parse_page函数,解析返回的网页数据,用Xpath提取所有字段内容,保存为csv格式。有人会问为什么J哥这么喜欢用Xpath,因为它简单好用!!!这么简单的网页结构,我不能做一个普通的大法来安装x。J弟兄,我做不到。

  def parse_page(html):

try:

parse = etree.HTML(html) # 解析网页

items = parse.xpath('//*[@id="report"]/tbody/tr')

for item in items[1:]:

item = {

'a': ''.join(item.xpath('./td[1]/font/text()')).strip(),

'b': ''.join(item.xpath('./td[2]/font/text()')).strip(),

'c': ''.join(item.xpath('./td[3]/text()')).strip(),

'd': ''.join(item.xpath('./td[4]/text()')).strip(),

'e': ''.join(item.xpath('./td[5]/text()')).strip(),

'f': ''.join(item.xpath('./td[6]/div/text()')).strip(),

'g': ''.join(item.xpath('./td[7]/div/text()')).strip(),

'h': ''.join(item.xpath('./td[8]/text()')).strip(),

'i': ''.join(item.xpath('./td[9]/text()')).strip()

}

#print(item)

try:

with open('./law.csv', 'a', encoding='utf_8_sig', newline='') as fp:

# 'a'为追加模式(添加)

# utf_8_sig格式导出csv不乱码

fieldnames = ['a', 'b', 'c', 'd', 'e','f','g','h','i']

writer = csv.DictWriter(fp,fieldnames)

writer.writerow(item)

except Exception:

print(traceback.print_exc()) #代替print e 来输出详细的异常信息

except Exception:

print(traceback.print_exc())

  最后,遍历页数,调用函数。OK完成!

   for page in range(1,5): #这里设置想要爬取的页数

html = get_page(page)

#print(html)

print("第" + str(page) + "页提取完成")

  让我们看看最终的结果:

  二

  硒

  有心学习的朋友可能还想看看Selenium如何爬取AJAX动态加载的网页。J哥自然会满足你的好奇心。于是我赶紧新建了一个py文件,准备趁势利用Selenium爬下这个网站。

  首先,导入相关库。

  from lxml import etree

import time

from selenium import webdriver

from selenium. webdriver.support.wait import WebDriverWait

from selenium.webdriver.support import expected_conditions as EC

from selenium.webdriver.common.by import By

  然后,使用 chromedriver 驱动程序打开这个 网站。

  def main():

# 爬取首页url

url = "http://www.hshfy.sh.cn/shfy/gweb2017/flws_list.jsp?ajlb=aYWpsYj3D8crCz"

# 定义谷歌webdriver

driver = webdriver.Chrome('./chromedriver')

driver.maximize_window() # 将浏览器最大化

driver.get(url)

  所以,我惊讶地发现这是错误的。有了六级英语的词汇储备,J哥居然听懂了!可能是我的驱动和浏览器的版本不匹配,只支持79版本的浏览器。

  J哥很郁闷,因为我之前从来没有遇到过Selenium for爬虫的这种问题。J哥不甘心,打开谷歌浏览器看了看版本号。

  我失去了它!全部更新到81版!遇到这种情况,请好奇的朋友等J哥设置浏览器自动更新重新下载最新驱动,下次再来听Selenium爬虫,记得关注这个公众号,不要'错过了~

  结语

  综上所述,对于AJAX动态加载的网络爬虫,一般有两种方式:解析接口;硒。J哥推荐解析接口的方式。如果解析的是json数据,爬起来会更好。真的没有办法使用 Selenium。

  参考链接:

  阿贾克斯:;

  ajax_json:;

  例子:

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线