动态网页抓取(什么是动态网页爬取的响应信息?寻找我们想要的结果 )
优采云 发布时间: 2021-12-10 06:05动态网页抓取(什么是动态网页爬取的响应信息?寻找我们想要的结果
)
上一篇文章简单介绍了静态网页的爬取,今天给大家分享一些动态网页爬取的技巧。什么是动态网页?举个很常见的例子,当我们在浏览网站的时候,随着我们不断向下滑动网页,当前页面会不断刷新新的内容,但是浏览器地址栏上的URL却一直没有改变。这种由JavaScript动态生成的页面,当我们通过浏览器查看其网页源代码时,往往找不到页面显示的内容。
抓取动态页面有两种常用的方法。一是通过JavaScript逆向获取动态数据接口(真实访问路径),二是使用selenium库模拟真实浏览器获取JavaScript渲染的内容。但是selenium库使用起来比较麻烦,爬取速度也比较慢,所以日常用的比较多的是第一种方法。
在做JS反向转发之前,首先要学会使用浏览器抓包。以Chrome浏览器为例打开网易新闻首页
右键查看网页源代码与按F12打开开发者工具看到的源代码不同,当我们下拉页面时,开发者工具中的源代码还在不断增加。这是JS渲染后的源码。也是当前网站显示内容的源码。
如上图所示,Network选项卡主要用于抓包的时候。按F5刷新页面后,下方显示框中会出现很多包。我们可以使用上面的过滤器栏对这些包进行分类。
这里主要使用XHR和JS两种。比如选择XHR,点击过滤后的第一个包。显示界面如下,右侧会出现一排选项卡。Headers 收录当前包的请求消息头和响应消息头。; Preview是响应消息的预览,Response是服务器响应的代码。
了解了这些之后,我们依次点击XHR和JS下的所有包,通过Preview预览当前包的响应信息,找到我们想要的结果。比如我们在下面的包中找到了文章列表,通过Headers找到了Request URL。这是我们真正应该请求的路径。
滚动页面的时候发现JS下添加了如下包和新的Request URL。与之前的相比,很容易找到一个通用的URL。分析完这个,我们就可以开始写代码了。
直接编码
import requests
from bs4 import BeautifulSoup
import json
import re
import multiprocessing
import xlwt
import time
def netease_spider(headers, news_class, i):
if i == 1:
url = "https://temp.163.com/special/00804KVA/cm_{0}.js?callback=data_callback".format(news_class)
else:
url = 'https://temp.163.com/special/00804KVA/cm_{0}_0{1}.js?callback=data_callback'.format(news_class, str(i))
pages = []
try:
response = requests.get(url, headers=headers).text
except:
print("当前主页面爬取失败")
return
start = response.index('[')
end = response.index('])') + 1
data = json.loads(response[start:end])
try:
for item in data:
title = item['title']
docurl = item['docurl']
label = item['label']
source = item['source']
doc = requests.get(docurl, headers=headers).text
soup = BeautifulSoup(doc, 'lxml')
news = soup.find_all('div', class_='post_body')[0].text
news = re.sub('\s+', '', news).strip()
pages.append([title, label, source, news])
time.sleep(3)
except:
print("当前详情页面爬取失败")
pass
return pages
def run(news_class, nums):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36'}
tmp_result = []
for i in range(1, nums + 1):
tmp = netease_spider(headers, news_class, i)
if tmp:
tmp_result.append(tmp)
return tmp_result
if __name__ == '__main__':
book = xlwt.Workbook(encoding='utf-8')
sheet = book.add_sheet('网易新闻数据')
sheet.write(0, 0, '文章标题')
sheet.write(0, 1, '文章标签')
sheet.write(0, 2, '文章来源')
sheet.write(0, 3, '文章内容')
news_calsses = {'guonei', 'guoji'}
nums = 3
index = 1
pool = multiprocessing.Pool(30)
for news_class in news_calsses:
result = pool.apply_async(run, (news_class, nums))
for pages in result.get():
for page in pages:
if page:
title, label, source, news = page
sheet.write(index, 0, title)
sheet.write(index, 1, label)
sheet.write(index, 2, source)
sheet.write(index, 3, news)
index += 1
pool.close()
pool.join()
print("共爬取{0}篇新闻".format(index))
book.save(u"网易新闻爬虫结果.xls")
这里我们抓取了国内和国际版块,在每个版块方向滚动了所有文章 3次,通过文章详情页上的链接爬取了文章的内容,最后爬上了到 289 文章。
需要注意的是,过快的抓取频率会导致访问失败。建议每次都睡一会。此外,增加个人测试中的线程数也很有用。如果可能,您可以添加一个 ip 代理池。我以前用过免费ip。基本上可以使用的ip很少,所以还是要付费的。所有代码和数据已经上传到github,链接在GitHub
本文与微信公众号“NLP炼金术士”同步,感兴趣的同学可以扫码关注,获取更多内容。