自从这两天开始学爬虫,就一直想做个爬虫爬知乎。于是就开始动手了。
知乎用户动态采取的是动态加载的方式,也就是先加载一部分的动态,要一直滑道底才会加载另一部分的动态。要爬取全部的动态,就得先获取全部的url。
我先找到了第一条url:
https://www.zhihu.com/api/v4/members/***************************/activities?limit=7&session_id=************************&after_id=*************&desktop=True
为了不泄露别人的隐私。涉及到用户信息部分我都用*来代替。
通过几个url的比对,我找到个关键的信息after_id。
这个after_id是一串n位的数字,刚开始我以为每条url之间的after_id都是有规律的,但对比了几条url之后我发现这个数字完全没有规律。那没有规律的话该怎么找出下一个url呢?
情急之下我想到一个办法,我发现after_id前几位是不变的,一直改变的是后六位数字。于是我想到,能不能遍历十万个数,每次after_id加一,这样就能找出所有的url了。
这不太可行。
冷静下来我开始分析url。打开url之后我发现回复的json数据里有一个键值‘next’,里面放的就是下一次请求的url。只要不断提取next的值,就能拿到所有的url。于是我想到了递归的方法。难点解决了,剩下的其实很快就可以完成。下面的源码:
import re import os import requests import urllib import json allUrl=[] #全局数组,用来保存该用户所有的动态的urldef getUrl(url): #递归获取用户所有的动态url nextUrl=urllib.request.urlopen(url) nextUrl=json.loads(nextUrl.read()) key=nextUrl['paging'] if 'next' in key: #假如还没到底 nextUrl=nextUrl['paging']['next'] allUrl.append(nextUrl) #print(nextUrl) getUrl(nextUrl) else: #已经到底,停止递归 print('成功获取所有url!') return def getArticle(): #获取文章,并将文章存入文本文件中 a='' cnt=0 for line in allUrl: t=urllib.request.urlopen(line) t=json.loads(t.read()) t=t['data'] try: #异常处理,由于未知原因,爬取某个url时会出现找不到json数据里的content键,导致报错 for k in t: #提取单个url内所有文章 k1=k['target']['content'] k1=re.sub('.*?</figure>','\r\n\r\n',k1) k1=k1.replace('</p><p>','\r\n ') k1=k1.replace('</p>','\r\n') k1=k1.replace('<p>','') k1=k1.replace('<br>','') cnt=cnt+1 a=a+k1 print('第'+str(cnt)+'个动态爬取成功') except KeyError: print('发生错误,此时的url为'+str(line)) file=open('D:/bbb.txt','w',encoding='gb18030',errors='ignore') #将内容写入文本,字符编码要与浏览器一致,否则会报错。 file.write(a) file.close() getUrl(url) #参数是第一个url getArticle()