大概是一个星期之前,我舍友曾让我爬一下知乎几个问题下的所有回答,想看看能不能找到他记忆中的那一条。

虽然这个要求不难,只要把所有的回答内容爬下来再查询一下就可以轻松搞定;但由于当时我只会requests和pandas,不会用任何的数据库,所以这对我来说还是一个特别棘手的事情。我原计划是把所有回答的id和content作为元组加到一个列表里,再用pandas生成dataframe或是Excel。

看似很轻松,不过每一条问题的回答都有三万多条,我一不会多线程/进程,二不会数据库,爬得慢不说,一旦宕机就又得从头做起,那时候我整整弄了两个小时,真是令人头大。

所以我今天重写了一下,虽然还是很乱很简单,却节省了90%的时间。

import pymongo,requests
import multiprocessing as mp

#要抓取的问题的链接
url = 'https://www.zhihu.com/api/v4/questions/277508190/answers?'
#headers和下面的params都可以在Chrome的Network中找到,有关隐私的部分已被我用XXXXXXXXXXXXXXXX代替
headers = {
    'user-agent''Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}

#offset偏移量,代表每次从第几条回答开始,由于回答数为33018,且每次最多获取20条回答,所以设置最大值为33018,步长20
offset = [offset for offset in range(0,33018,20)]
#连接MongoDB数据库
myclient = pymongo.MongoClient('mongodb://localhost:27017')
#新建“Zhihu”表
Zhihu = myclient['Zhihu']
#新建“Answer”集合
Answer = Zhihu['Answer']

#获取20条答案的Json
def get_answer_json(offset):
    params = {
    'include''XXXXXXXXXXXXXXXX',
    'offset': offset,
    'limit'20,
    'sort_by''default',
    'platform''desktop'
    }
    r = requests.get(url,headers=headers,params=params).json()
    return r['data']
#将获取的Json写入数据库
def save_to_DB(offset):
    data = get_answer_json(offset)
    Answer.insert_many(data)
    print('已完成{}条回答的采集。'.format(offset+20))

if __name__ == '__main__':
    #多进程运行save_to_DB
    p = mp.Pool()
    p.map_async(save_to_DB,offset)
    p.close()
    p.join()

因为登录了账号,所以没有用proxies。

有点心急,没有加time.sleep。