当前位置: 首页 > 后端技术 > Python

爬虫:动态网页列表流数据越来越多(通过Ajax获取微博个性化推荐内容)

时间:2023-03-26 16:00:04 Python

浏览社交媒体时,我们看到的内容似乎无穷无尽。我们经常滑到页面底部,以为没有内容,却发现一下子刷新了新内容。内容越来越溜,这种数据叫做列表流数据。有趣的是,虽然页面不断为我们提供新内容,但网页保持不变——URL没有改变。这是怎么回事?1同一页面中的Ajax,网页如何不断显示新内容?如果我们打开浏览器的开发者模式,当我们滚动到页面底部时,我们可以在“网络”选项卡中观察到一些新生成的xhr类型的条目。这些条目中包括Ajax请求。据崔庆才老师介绍:Ajax,全称AsynchronousJavaScriptandXML,即异步JavaScript和XML。它不是一种编程语言,而是一种使用JavaScript与服务器交换数据,更新一些网页,同时保证页面不刷新,页面链接不变的技术。对于传统的网页来说,如果要更新它的内容,就必须刷新整个页面,但是有了Ajax,你可以更新它的内容,而不用完全刷新页面。在这个过程中,页面实际上是在后台与服务器进行数据交互。获取数据后,使用JavaScript改变网页,从而更新网页内容。简单的说,当我们向下滑动到页面底部时,JavaScript会在网页后台向服务器发送请求,告诉服务器我们想要更多的内容。服务器返回相应的响应内容,JavaScript解析响应内容(无论是HTML格式还是JSON格式)渲染成我们看到的新内容。2、爬取列表流数据:以微博为例,了解列表流数据是如何不断生成的,我们有一个获取这类数据的思路:模拟JavaScript向Web服务器发送Ajax请求,分析获取响应数据。下面演示一下爬取过程——以爬取微博个性化推荐内容为例。2.1观察Ajax请求我们找到上面提到的xhr文件,点击它,我们可以看到文件中包含的header信息。相关资料包括:RequestURL:如果观察多个xhr条目,会发现它们的url几乎完全相同,唯一不同的是max_id的值,从1开始,每次从下往上刷新,新的xhr条目的max_idvalue加1。请求方法状态码为请求头中的cookie,请求头中的user-agent为x-requested-with,其值为XMLHttpRequest,将请求标记为Ajax请求。除了标头之外,我们还可以观察到Ajax请求的预览,它是一个JSON文件。可以看出,这个请求包含了10条内容。如果我们深入查看一条内容,可以找到这条内容对应的微博信息,包括微博id、发布用户、微博文字内容、微博图片内容、发布微博的IP地址信息等。2.2爬取Ajax请求得到的JSON数据现在我们可以尝试爬取上面的数据。首先导入我们需要的包,定义一些后面要用到的变量:fromurllib.parseimporturlencodeimportrequestsfrompyqueryimportPyQueryaspqbase_url='https://weibo.com/ajax/feed/hottimeline?'#本项目需要爬取的url都是以这个开头的headers={'User-Agent':'YourUser-Agent',#点击你要爬取的xhr文件,在header中可以找到相关信息。'X-Requested-With':'XMLHttpRequest','Cookie':'YourCookie'}让我们构建一个函数,返回我们想要发送模拟请求的URL:defget_hottimeline_url(max_id):'''返回一个Thexhr类型“hottimeline”的url。:parammax_id:每个热点时间线url中的特殊max_id(1,2,3...)'''params={'refresh':'2','group_id':'group_idinyourURL','containerid':'group_idcontaineridinyourURL','extparam':'discover%7Cnew_feed','max_id':max_id,#只有这个值在URL中改变'count':'10'}url=base_url+urlencode(params,safe='%')#这里指定safe参数,这样“%”就不会被转义为“%25”,否则会拼接成错误的URLreturnurl接下来我们获取静态页面的数据,发送一个请求通过request获取json数据:defget_response_json(url):'''返回一个url的json文件。'''response=requests.get(url,headers=headers)json=response.json()returnjson2.3解析JSON数据获取到JSON数据后,我们需要对数据进行解析,得到我们需要的信息。一个URL可以返回10条微博内容,我们希望循环获取每条微博内容的数据,保存为字典。然后将这个字典存入微博内容组成的列表中。在获取一条微博的文字内容时,需要注意的是,当这条微博的文字内容过长时,会折叠文字段。如果我们想看到完整的内容,需要在浏览器界面点击“展开”按钮,这使得我们无法在已有的JSON数据中获取到完整的文本数据。但是,当我们点击展开时,可以看到在开发者模式的网络选项卡中多了一个名为“longtext?id=xxxxxxxxxx”的xhr入口。我们可以通过这个录入数据的URL得到完整的长文本。defparse_hottimeline(list_recommendation,json):'''解析hottimelinejson文件并将10个热门列表推荐附加到内容列表。'''foriteminjson.get('statuses'):weibo={}#创建临时字典,用于保存微博信息#用户信息user_info=item.get('user')weibo['user_id']=user_info.get('id')#发布者idweibo['user_name']=user_info.get('screen_name')#发布者昵称#微博信息weibo['id']=item.get('id')#微博idweibo['isLongText']=item.get('isLongText')#当该变量为True时,该微博正文为长文本(正文段会折叠)weibo['mblogid']=item.get('mblogid')#通过这个变量,如果weibo['isLongText']为True,可以索引到长文本的JSON文件的URL:url="https://weibo.com/ajax/statuses/longtext?id="+weibo['mblogid']json_longtext=get_response_json(url)weibo['text']=json_longtext.get('data').get('longTextContent')else:weibo['text']=pq(item.get('text')).text()weibo['pic_num']=item.get('pic_num')#这条微博包含的图片数量weibo['pic']=[]#用于保存url微博图片ifweibo['pic_num']>0:pic_dict=item.get('pic_infos')forpicinpic_dict:pic_url=pic_dict[pic]['original']['url']weibo['pic'].append(pic_url)else:passweibo['attitudes']=item.get('attitudes_count')#点赞数weibo['comments']=item.get('comments_count')#评论数weibo['reposts']=item.get('reposts_count')#转发数region=item.get('region_name')#发布时的IP地址ifregionisNone:weibo['region']=regionelse:weibo['region']=region.strip('PublishYu')print(weibo)list_recommendation.append(weibo)#将分析过的微博数据添加到列表中2.4存储数据我们实现了页面底部刷新数据的URL获取,模拟请求,解析数据functions最后,我们会新建一个列表,将每一条微博信息存储在里面。main函数代码如下:if__name__=='__main__':list_recommendation=[]formax_idinrange(1,11):#模拟爬取10条刷新结果,最终得到100条个性化推荐热门微博数据hottimeline_url=get_hottimeline_url(max_id)print('hottimeline_url=',hottimeline_url)response_json=get_response_json(hottimeline_url)parse_hottimeline(list_recommendation,response_json)参考Python3网络爬虫开发实践-6Ajax数据爬取(崔庆才)注:转载请注明出处。