网页分析

首先我们打开知乎官网https://www.zhihu.com/,选择热榜,我们选取当前热榜第一的问答美国四年来首次公布该国核弹头数量为 3750 枚,这一数据透露了哪些信息?进行分析和爬取。

首先依旧F12打开网页的分析界面,通过定位可以看到网页的代码中对应回答的文本
在这里插入图片描述

接着右键查看源代码,可以看到源代码中有对应的回答,但是逐步看下去的话会发现只有前两个回答,而总共的回答有两百多个(回答数会随着时间的增加而增加),可以确定前端页面的加载是AJax加载出来的,简而言之就是一个问题下面可能会有许多回答,如果一下子把所有的回答都加载出来,可能会很慢,所以先传递给HTML页面一部分回答。当用户下拉滚动条或者展开所有回答的时候,触发执行一个程序,这时程序会继续向服务器请求余下的数据包。
首先我们找到具体
在Chrome调试模式选择Network—XHR,可以找到回答全部存在这个以answer开头的文件中
在这里插入图片描述

在Preview中我们可以看到答案在data下的序号中,每一个序号对应一个回答,回答内容在Content中。
但是在一个文件中我们可以看到只有 五个回答,而这个问题下总共有549 个回答,从这边可以看出还有其他的回答文件,而找到其他的回答数据有两种方法:
第一种在之前包含回答的json文件的最后我们可以看到有对应的paging信息,里面注明了是否为起始和结束的文件,并包含上一个和下一个文件的请求地址。所以我们只需要通过这个文件一直向前和向后找到最前和最后的文件即可
在这里插入图片描述
第二种方法我们可以根据已有的json请求地址对比,发现除了最后的offset不同外其他的都是一致的,而且每一个相差5。因此我们也可以通过直接构造URL请求数据.作为测试,我们将其中的offect改为0并请求后得到数据如下,可以验证这种方法是可行的:
在这里插入图片描述

爬取步骤

首先我们先构造请求头并尝试请求对应的地址,发现可以正确的返回回答的内容:

import requests

start_url = "https://www.zhihu.com/api/v4/questions/490840493/answers?include=data%5B%2A%5D.is_normal%2Cadmin_closed_comment%2Creward_info%2Cis_collapsed%2Cannotation_action%2Cannotation_detail%2Ccollapse_reason%2Cis_sticky%2Ccollapsed_by%2Csuggest_edit%2Ccomment_count%2Ccan_comment%2Ccontent%2Ceditable_content%2Cattachment%2Cvoteup_count%2Creshipment_settings%2Ccomment_permission%2Ccreated_time%2Cupdated_time%2Creview_info%2Crelevant_info%2Cquestion%2Cexcerpt%2Cis_labeled%2Cpaid_info%2Cpaid_info_content%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%2Cis_recognized%3Bdata%5B%2A%5D.mark_infos%5B%2A%5D.url%3Bdata%5B%2A%5D.author.follower_count%2Cvip_info%2Cbadge%5B%2A%5D.topics%3Bdata%5B%2A%5D.settings.table_of_content.enabled&limit=5&offset=5&platform=desktop&sort_by=default"
#请求头
self_header={'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36'}
#用request库进行请求并获取返回文本
response = requests.get(start_url , headers=self_header, timeout=30)
response.raise_for_status()
response.encoding = response.apparent_encoding
con=response.text
print(con)

接下来对获取的json数据进行解析。由于回答数据中包含前端标签,因此利用正则表达式去除:

con= json.loads(response.text)
#提取回答数据
answers = [item["content"] for item in con["data"]]
for answer in answers:
    #原回答中带有html标签,利用正则表达式去除
    answer=re.sub("<.*?>","",answer)
    print(answer)

运行后成功得到了回答数据,接下来需要遍历所有的url,从而获取到所有的回答。由于我们采用的是改动URL中的offest参数方式,所以首先可以从json数据中获取回答总数
在这里插入图片描述
遍历后即可得到所有的回答:
在这里插入图片描述
同时每个回答的对应其他信息也可以在json文件中找到.例如点赞数在对应回答下的voteup_count中,评论数量在comment_count中。
使用第一种方法也是一样的原理,只需要每次获取json数据中的上一个url和下一个url即可,小伙伴们有兴趣可以尝试一下。

完整源码可于公众号后台回复“知乎爬虫”获取