数据采集实战:动态网页数据采集

优采云 发布时间: 2022-05-04 17:00

  数据采集实战:动态网页数据采集

  Part1引言

  我们上一篇推文中,已经讲解了静态网页的采集方法,本文我们介绍动态网页采集的方法。

  本文采集的示例网站为:,我们的目标是将网页中指定的文本信息采集下来并保存。

  完整的代码请见文末附件!

  Part2什么是动态网页

  通常情况下,我们要提取的数据并不在我们下载到的HTML源代码中。举个例子,我们在刷QQ空间或者微博评论的时候,一直往下刷,网页在不刷新的情况下会越来越长,内容也越来越多。

  具体而言,当在我们浏览网站的时候,更具用户的实际操作(如鼠标滚轮下滑加载内容),不断的向服务器发起请求,并将请求回来的数据利用JavaScript技术,将新的内容添加到网页中。以百度图片为例子:,我们进入百度图片之后,搜索我们想要查找的图片进行搜索,随后不断地下滑页面,我们会看到网页中不断有图片加载出来,但是网页并没有刷新,这就动态加载页面。

  Part3手动采集的操作步骤

  本文采集的示例网站为:,内容如下图所示:

  

  假设我们需要采集的内容有:文章的标题、关键词、发布日期和详情链接这4部分内容,对于标题、关键词、发布日期这3个信息我们在列表页中就可以看到。对于详情链接,我们还需要在网站上点击指定详情页之后,才能采集,如下图:

  

  假设我们想要采集的内容有很多,光靠手动采集的操作会浪费大量的时间,所以我们可以利用Python自动化采集数据。

  Part4自动采集的操作步骤(一)分析动态加载的页面

  在不刷新网页的情况下,该网站是需要点击网页末尾的按钮,才会加载新的数据,如下图所示:

  

  我们打开开发者工具(谷歌浏览器按F12),点击过滤器XHR,然后多次点击网页最下方按钮进行内容的加载,我们可以看到,每次点击按钮之后,就能抓到一个包,我们查看抓包的信息,就能发现,该请求返回的响应内容里面就有我们想要的数据,实际的操作如下图:

  

  网页中显示的内容:

  

  所以我们可以直接请求该接口来获取我们想要的数据,我们先将这三个不同请求的URL提取出来,如下所示:

  第2页:https://www.xfz.cn/api/website/articles/?p=2&n=20&type=<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />第3页:https://www.xfz.cn/api/website/articles/?p=3&n=20&type=<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />第4页:https://www.xfz.cn/api/website/articles/?p=4&n=20&type=

  Tip:,该URL是GET请求带参数的情况,域名和参数之间用?隔开,每个参数之间用&amp;间隔。

  我们观察每一页的URL参数的变化,发现在三个参数里面p为变化的参数,每点击一次,p就自增1,所以p参数跟翻页有关,我们可以通过修改p参数,来访问不同页面的信息内容,我们也可以推断出,当p参数的值为1的时候,就是请求网站第1页的内容。

  (二)代码实现1. 请求页面并解析数据

  import requests<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />import time<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" /><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />for page in range(1, 6):  # 获取5页数据<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    # 利用format构造URL<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    url = 'https://www.xfz.cn/api/website/articles/?p={}&n=20&type='.format(page)<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    # 发送请求获取响应<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    res = requests.get(url=url)<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    # 将响应的json格式字符串,解析成为Python字典格式<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    info_dic = res.json()<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    # 提取我们想要的数据,并格式化输出<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    for info in info_dic['data']:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        result = {<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />            'title': info['title'],<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />            'date': info['time'],<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />            'keywords': '-'.join(info['keywords']),<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />            'href': 'https://www.xfz.cn/post/' + str(info['uid']) + '.html'<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        }<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        print(result)<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    time.sleep(1)  # 控制访问频率<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />

  执行结果(部分):

  {'title': '「分贝通」完成C+轮1.4亿美元融资', 'date': '2022-02-17 10:17:13', 'keywords': '分贝通-DST Global', 'href': 'https://www.xfz.cn/post/10415.html'}<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />{'title': '「塬数科技」完成近亿元A轮融资,凡卓资本担任独家财务顾问', 'date': '2022-02-15 10:17:42', 'keywords': '塬数科技-凡卓资本-晨山资本-博将资本', 'href': 'https://www.xfz.cn/post/10412.html'}<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />{'title': '「BUD」获1500万美元A+轮融资', 'date': '2022-02-14 10:15:35', 'keywords': '启明创投-源码资本-GGV纪源资本-云九资本', 'href': 'https://www.xfz.cn/post/10411.html'}<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />{'title': '以图计算引擎切入千亿级数据分析市场,它要让人人成为分析师,能否造就国内百亿级黑马', 'date': '2022-02-10 11:04:52', 'keywords': '欧拉认知智能-新一代BI', 'href': 'https://www.xfz.cn/post/10410.html'}<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />{'title': '前有Rivian市值千亿,后有经纬、博原频频押注,滑板底盘赛道将诞生新巨头?丨什么值得投', 'date': '2022-02-09 11:51:36', 'keywords': '什么值得投', 'href': 'https://www.xfz.cn/post/10409.html'}<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />

  2. 保存到本地csv

  我们在原先的代码基础上,添加一点内容,将我们爬取下来的内容保存到CSV文件中,保存到CSV文件的方法有许多种,这边采用pandas第三方模块来实现,需要pip install pandas进行安装。

  import requests<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />import time<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />import pandas as pd  # 导入模块<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" /><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" /># 创建一个数据集,用来保存数据<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />data_set = [<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ('标题', '日期', '关键词', '详情链接'),  # 这边先定义头部内容<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />for page in range(1, 6):  # 获取5页数据<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    # 利用format构造URL<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    url = 'https://www.xfz.cn/api/website/articles/?p={}&n=20&type='.format(page)<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    # 发送请求获取响应<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    res = requests.get(url=url)<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    # 将响应的json格式字符串,解析成为Python字典格式<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    info_dic = res.json()<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    # 提取我们想要的数据,并格式化输出<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    for info in info_dic['data']:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        result = {<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />            'title': info['title'],<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />            'date': info['time'],<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />            'keywords': '/'.join(info['keywords']),  # 关键词会含有多个,每个关键词用斜杠隔开<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />            'href': 'https://www.xfz.cn/post/' + str(info['uid']) + '.html'  # 构造详情页url<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        }<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        # 获取字典里面的值,并转换成列表<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        info_list = list(result.values())<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        # 添加到数据集<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        data_set.append(info_list)<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    time.sleep(1)  # 控制访问频率<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" /><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" /># 保存成为csv文件<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />df = pd.DataFrame(data_set)<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />df.to_csv('xfz.csv', mode='a', encoding='utf-8-sig', header=False, index=False)<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />

  执行结果(部分):

  

  Part5总结

  文本讲述了动态网站数据采集基本流程与方法,结合我们上一期讲的静态网页数据的采集实战,相信大家已经掌握了数据采集的基本技能。那么数据采集回来如何处理呢?敬请期待下期推文:Python数据处理基本方法。

  附件:get_web_data.py

  import requests<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />import time<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />import pandas as pd  # 导入模块<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" /><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" /># 创建一个数据集,用来保存数据<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />data_set = [<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    ('标题', '日期', '关键词', '详情链接'),  # 这边先定义头部内容<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />]<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />for page in range(1, 6):  # 获取5页数据<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    # 利用format构造URL<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    url = 'https://www.xfz.cn/api/website/articles/?p={}&n=20&type='.format(page)<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    # 发送请求获取响应<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    res = requests.get(url=url)<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    # 将响应的json格式字符串,解析成为Python字典格式<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    info_dic = res.json()<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    # 提取我们想要的数据,并格式化输出<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    for info in info_dic['data']:<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        result = {<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />            'title': info['title'],<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />            'date': info['time'],<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />            'keywords': '/'.join(info['keywords']),  # 关键词会含有多个,每个关键词用斜杠隔开<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />            'href': 'https://www.xfz.cn/post/' + str(info['uid']) + '.html'  # 构造详情页url<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        }<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        # 获取字典里面的值,并转换成列表<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        info_list = list(result.values())<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        # 添加到数据集<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />        data_set.append(info_list)<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />    time.sleep(1)  # 控制访问频率<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" /><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" /># 保存成为csv文件<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />df = pd.DataFrame(data_set)<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />df.to_csv('xfz.csv', mode='a', encoding='utf-8-sig', header=False, index=False)<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;" />

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线