python抓取动态网页(Python网络爬虫从入门到实践(第2版)作者博客的HelloWorld文章为例)
优采云 发布时间: 2022-03-17 23:07python抓取动态网页(Python网络爬虫从入门到实践(第2版)作者博客的HelloWorld文章为例)
内容
1 动态爬取技术介绍
AJAX(Asynchronous Javascript And XML)的价值在于可以通过在后台与服务器交换少量数据来异步更新网页。这意味着可以在不重新加载整个页面的情况下更新页面的某些部分。一方面减少了网页重复内容的下载,另一方面节省了流量,因此AJAX得到了广泛的应用。
有两种动态网页抓取方法可以从使用 AJAX 加载的动态网页中抓取动态加载的内容:
2 解析真实地址抓取
以《Python网络爬虫从入门到实践(第2版)》作者博客的Hello World文章为例,目标是抓取文章下的所有评论。文章网址是:
步骤 01 打开“检查”功能。在 Chrome 浏览器中打开 Hello World文章。右键单击页面任意位置,在弹出的弹出菜单中单击“检查”命令。
Step 02 找到真正的数据地址。单击页面中的网络选项并刷新网页。此时,Network 将显示浏览器从 Web 服务器获取的所有文件。一般这个过程就变成了“抓包”。
从文件中快速找到评论数据所在文件的方法: 搜索评论内容可以快速定位到具体评论所在的文件。
Step 03 爬取真实评论数据地址。既然找到了真实地址,就可以直接使用requests请求这个地址来获取数据了。
步骤 04 从 json 数据中提取注释。您可以使用 json 库来解析数据并从中提取所需的数据。
import requests
import json
link = "https://api-zero.livere.com/v1/comments/list?callback=jQuery112408626354130815113_1646567623361&limit=10&repSeq=4272904&requestPath=/v1/comments/list&consumerSeq=1020&livereSeq=28583&smartloginSeq=5154&code=&_=1646567623363"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36'}
r = requests.get(link, headers=headers)
# 获取json的string
json_string = r.text
json_string = json_string[json_string.find('{'):-2] # 从第一个左大括号提取,最后的两个字符-括号和分号不取
json_data = json.loads(json_string)
comment_list = json_data['results']['parents']
for eachone in comment_list:
message = eachone['content']
print(message)
接下来可以使用for循环爬取多页评论数据。可以对比不同页面的真实地址,找出参数的差异,改变discount参数的值来切换页面。
import requests
import json
def single_page_comment(link):
headers = {
'User-Agent': 'https://api-zero.livere.com/v1/comments/list?callback=jQuery112407919796508302595_1646571637355&limit=10&offset=2&repSeq=4272904&requestPath=/v1/comments/list&consumerSeq=1020&livereSeq=28583&smartloginSeq=5154&code=&_=1646571637361'}
r = requests.get(link, headers=headers)
# 获取json的string
json_string = r.text
json_string = json_string[json_string.find('{'):-2] # 从第一个左大括号提取,最后的两个字符-括号和分号不取
json_data = json.loads(json_string)
comment_list = json_data['results']['parents']
for eachone in comment_list:
message = eachone['content']
print(message)
max_comments = 50 # 设置要爬取的最大评论数
for page in range(1,max_comments // 10 + 1):
link1 = "https://api-zero.livere.com/v1/comments/list?callback=jQuery112407919796508302595_1646571637355&limit=10&offset="
link2 = "&repSeq=4272904&requestPath=/v1/comments/list&consumerSeq=1020&livereSeq=28583&smartloginSeq=5154&code=&_=1646571637361"
page_str = str(page)
link = link1 + page_str + link2
print(link)
single_page_comment(link)
3 通过 Selenium 模拟浏览器抓取
有些网站非常复杂,使用“inspect”功能很难找到调用页面的URL。另外,有些数据的真实地址的URL也很复杂,有些网站为了避免这些爬取,会对地址进行加密,造成一些变量的混淆。因此,这里有另一个介绍。一种方法是使用浏览器渲染引擎。使用浏览器直接显示网页时解析 HTML、应用 CSS 样式和执行 JavaScript 的语句。通俗的讲,就是通过浏览器渲染的方式,把爬取的动态页面变成爬取的静态页面。
在这里,抓取是使用 Python 的 Selenium 库来模拟浏览器完成的。Selenium 是用于 Web 应用程序测试的工具。
3.1 Selenium 基本介绍
浏览器驱动下载地址:
铬合金:
Edge:Microsoft Edge 驱动程序 - Microsoft Edge 开发人员
Firefox:发布 · mozilla/geckodriver · GitHub
Safari:Safari 10 中的 WebDriver 支持 网络套件
使用Selenium打开浏览器和网页,代码如下:
from selenium import webdriver
driver = webdriver.Firefox()
driver.get("http://www.santostang.com/2018/07/04/hello-world/")
3.2 Selenium 实践案例
步骤 01 找到评论的 HTML 代码标签。使用Chrome打开文章页面,右键该页面,在弹出的快捷菜单中点击“检查”命令。
Step 02 尝试获取评论数据。对原打开页面的代码数据使用如下代码,获取第一条评论数据。
from selenium import webdriver
driver = webdriver.Firefox()
driver.get("http://www.santostang.com/2018/07/04/hello-world/")
# 转化iframe
driver.switch_to.frame(driver.find_element(by='css selector', value='iframe[title="livere-comment"]'))
# 获取css标签为div.reply-content
comment = driver.find_element(by='css selector', value='div.reply-content')
content = comment.find_element(by='tag name', value='p')
print(content.text)
3.3 Selenium 获取 文章 的所有评论
如果要获取所有评论,需要一个可以自动点击“+10查看更多”的脚本,这样所有评论才能显示出来。所以我们需要找到“+10 查看更多”的元素地址,然后让 Selenium 模拟点击并加载评论。具体代码如下:
from selenium import webdriver
import time
driver = webdriver.Firefox()
driver.implicitly_wait(10) # 隐性等待,最长等10秒
driver.get("http://www.santostang.com/2018/07/04/hello-world/")
time.sleep(5)
# 下滑到页面底部(左下角)
driver.execute_script("window.scrollTo(0,document.body.scrollHeight);")
print("wait for 3 seconds")
time.sleep(3)
for i in range(1, 19):
# 转换iframe,再找到查看更多,点击
driver.switch_to.frame(driver.find_element(by="css selector", value="iframe[title='livere-comment']"))
# load_more = driver.find_element(by="css selector", value="button[data-page=\'%d\']'%i")
if i > 11:
x_path = './/div[@class="more-wrapper"]/button[' + str(i - 9) + ']'
else:
x_path = './/div[@class="more-wrapper"]/button[' + str(i) + ']'
load_more = driver.find_element(by="xpath", value=x_path)
load_more.send_keys("Enter") # 点击前先按下Enter,可以解决因跳转点击时出现失去焦点而导致的click单击无效的情况
load_more.click()
# 把iframe又转回去
driver.switch_to.default_content()
print("Click and waiting loading --- please waiting for 5s")
time.sleep(5)
driver.switch_to.frame(driver.find_element(by="css selector", value="iframe[title='livere-comment']"))
comments = driver.find_elements(by="css selector", value="div.reply-content")
for each_comment in comments:
content = each_comment.find_element(by="tag name", value="p")
print(content.text)
driver.switch_to.default_content()
driver.execute_script("window.scrollTo(0,document.body.scrollHeight);")
time.sleep(2)
Selenium 中常用的元素操作方法如下:
from selenium import webdriver
import time
driver = webdriver.Firefox()
driver.implicitly_wait(10) # 隐性等待,最长等10秒
driver.get("http://www.santostang.com/")
time.sleep(5)
user = driver.find_element(by="name", value="username")
user.send_keys("123456")
pwd = driver.find_element(by="password") # 找到密码输入框
pwd.clear() # 清除密码输入框内容
pwd.send_keys("******") # 在框中输入密码
driver.find_element(by="id", value="loginBtn").click() # 单击登录
除了简单的鼠标操作,Selenium 还可以实现复杂的双击、拖放操作。此外,Selenium 还可以获取网页中每个元素的大小,甚至可以模拟键盘的操作。
3.4 Selenium 的高级操作
常用的加快Selenium爬取速度的方法有:
3.4.1 控制 CSS
在爬取过程中,只爬取页面的内容。CSS 样式文件用于控制页面的外观和元素的放置,对内容没有影响。因此,我们可以限制网页上 CSS 的加载,以减少爬取时间。其代码如下:
# 控制CSS
from selenium import webdriver
# 使用fp控制CSS的加载
fp = webdriver.FirefoxOptions()
fp.set_preference("permissions.default.stylesheet", 2)
driver = webdriver.Firefox(options=fp)
driver.get("http://www.santostang.com/2018/07/04/hello-world/")
3.4.2 限制图片加载
如果不需要抓取网页上的图片,最好禁止图片加载。限制图片加载可以帮助我们大大提高网络爬虫的效率。
# 限制图片的加载
from selenium import webdriver
fp = webdriver.FirefoxOptions()
fp.set_preference("permissions.default.image", 2)
driver = webdriver.Firefox(options=fp)
driver.get("http://www.santostang.com/2018/07/04/hello-world/")
3.4.3 控制 JavaScript 的执行
如果要爬取的内容不是通过 JavaScript 动态加载的,我们可以通过禁止 JavaScript 的执行来提高爬取的效率。因为大多数网页使用 JavaScript 异步加载大量内容,我们不仅不需要这些内容,而且加载它们会浪费时间。
# 限制JavaScript的执行
from selenium import webdriver
fp=webdriver.FirefoxOptions()
fp.set_preference("javascript.enabled",False)
driver=webdriver.Firefox(options=fp)
driver.get("http://www.santostang.com/2018/07/04/hello-world/")
参考
[1] 唐松.2019.Python网络爬虫从入门到实践(第2版)[M]. 北京:机械工业出版社