最近在自学python爬虫,就会那么几个常用的库的基本动作,拿来爬知乎试一下效果,发现还能爬下来点数据,当然,只是娱乐级别。
首先想了一下爬用户的思路。
先选一个优质用户,从他的粉丝列表或者关注的人列表中获取用户,鉴于有很多像我这样并没有粉丝的账号,因此选择从关注的人列表中下手。从这位大号关注的人列表中获取每一位用户,再查找每位用户关注的人。。。以此类推。老子曰“道生一,一生二,二生三,三生万物”? 记住,是老子,不是老子。
下面我打开一个大号,并按F12打开元素审查工具。
可以看到他关注了3000多人,够我发展下线了。点击 关注了 打开他关注的人列表,同时观察右边内容的变化。
让我费了很大力气分析了半天发现,其中一个请求的响应包含了很多字典形式的用户信息,这就是大号关注列表里的人的信息。
顺便还发现paging里是关注列表翻页信息。。。
下面就要分析每个用户的详细信息怎么获取了。
本来想着打开用户首页,获取HTML 然后 解析一下详细信息很简答,但是实践发现貌似解析不出来。。。详细信息可能是动态加载的,好吧,暂时还不会。
后来发现把鼠标放在列表中人名上边,浏览器会有GET请求,并返回一些内容。就抓这些吧。。。
分析两个请求的链接发现,获取的信息里url_token字段在网址里确定了是哪个用户。要做的就是获取不同的url_token给程序,然后获取不同的用户信息。
下面是代码,初级的不能再初级版,修修补补反正能跑起来。
知乎爬一会会出403错误,让输验证码,不会跳过,只能手动网页里输,然后继续程序。。。
import requests
import json
import random
import time
import re
import pymongo
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0',
#'Accept-Encoding': 'gzip, deflate, br',
'Referer': 'https://www.zhihu.com/',
#'Cookie': 'q_c1=298c1fa0e68f45628ed33b56cbec7b7d|1528555970000|1486913150000; d_c0="AGACAjPPTAuPTsPRgAxVrAX7cFDRM_NNabE=|1486913150"; __utma=51854390.779970699.1486913148.1486913148.1528556224.2; __utmv=51854390.000--|3=entry_date=20170212=1; _xsrf=97cefc40-23e7-4fa4-a378-b1978f5d039a; capsion_ticket="2|1:0|10:1528556751|14:capsion_ticket|44:NmNhZjBmZjM1MDdmNGE0NzlmZjk1NDgxZTQ4N2E4ZGE=|3ed5af9b2c394f8d944875582c6b7873c8954cdbf5cde0ebd3952be3d147682e"; _zap=9cde8426-ecd8-4f9e-bc0e-b42be17e598d; _ga=GA1.2.779970699.1486913148; _gid=GA1.2.994518661.1528556082; l_n_c=1; l_cap_id="YTNmZThjMTI3ODBmNDNkNTgwNmQzYmQ2NmQyMzM0MmQ=|1528556222|166e03fcf0b936700a7ee95fd5da3458ae7d71d4"; r_cap_id="NDIzNTdmZjQ4MWM2NDcyN2JhZTBmMTEwNWE5YjU5ZDE=|1528556222|63bf765d324f29e85b249f84ebad50be0b889dce"; cap_id="MDBiZDI3NzUzMmQ4NGIzYjg5MTM2MjJjMTA1OTdmOWQ=|1528556222|95de0c73df9e0c91e9a46f65e55043d1e6112107"; n_c=1; __utmb=51854390.0.10.1528556224; __utmc=51854390; __utmz=51854390.1528556224.2.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); tgw_l7_route=ec452307db92a7f0fdb158e41da8e5d8',
'Connection': 'keep-alive',
'authorization': 'oauth c3cef7c66a1843f8b3a9e6a1e3160e20',
'x-udid': 'AGACAjPPTAuPTsPRgAxVrAX7cFDRM_NNabE='
}
follow_url = 'https://www.zhihu.com/api/v4/members/{url_token}/followees?include=data[*]&offset=0&limit=20'
star_follow_url = 'https://www.zhihu.com/api/v4/members/houzichedan/followees?include=data[*]&offset=0&limit=20'
data_url= 'https://www.zhihu.com/api/v4/members/{url_token}?include=allow_message,is_followed,is_following,is_org,is_blocking,employments,answer_count,follower_count,articles_count,gender,badge[?(type=best_answerer)].topics'
#include = 'allow_message,is_followed,is_following,is_org,is_blocking,employments,answer_count,follower_count,articles_count,gender,badge[?(type=best_answerer)].topics'
# 1.连接数据库服务器,获取客户端对象
mongo_client= pymongo.MongoClient('localhost', 27017)
# 2.获取数据库对象
db= mongo_client.zhihu
# 3.获取集合对象
mongo= db.userdata
#db.getCollection('userdata').find({employments:{$elemMatch:{$ne:null}}})查询非空数组
n=1
def start_url(url=star_follow_url):
#用大号的关注列表请求页当爬虫的起始页
res = requests.get(url, headers=headers)
html = json.loads(res.text)
if res.status_code == 200:
for token in html['data']:
ut=token['url_token']
follows(ut)#调用follows函数,follows函数调用start_url函数,完成递归,一直循环
if html['paging']['is_end'] == False:
#根据paging字段的内容判断是否翻页
print('下一页')
start_url(url=html['paging']['next'])
if res.status_code == 403:
print(html['error']['redirect'])
print('s403')
indata = input('点击链接输入验证码后回车:')
#尝试在程序运行界面直接提交验证码,但是并不成功。
# sdata = {'captcha': indata}
# sdata = json.dumps(sdata)
# u = "https://www.zhihu.com/api/v4/anticrawl/captcha_appeal"
# requests.post(u, data=sdata, headers=headers)
return start_url(url)
def follows(ut):
#获取每一个关注的人的url_token,再获取每一个关注的人的关注列表
global n
url = follow_url.format(url_token=ut)
res = requests.get(url, headers=headers, allow_redirects=False)
html = json.loads(res.text)
if res.status_code == 200:
for token in html['data']:
#print(token['url_token'])
data(token['url_token'])
if html['paging']['is_end'] == False:
# 根据paging字段的内容判断是否翻页
print('下一页')
start_url(url=html['paging']['next'])
if res.status_code == 403:
print(html['error']['redirect'])
print('f403')
indata = input('点击链接输入验证码后回车:')
# 尝试在程序运行界面直接提交验证码,但是并不成功。
# sdata = {'captcha': indata}
# sdata = json.dumps(sdata)
# u = "https://www.zhihu.com/api/v4/anticrawl/captcha_appeal"
# requests.post(u, data=sdata ,headers=headers)
# time.sleep(1)
return follows(ut)
def data(ut):
#获取每一个urltoken的用户资料,存入数据库
global n
url = data_url.format(url_token=ut)
print("=============================================================================")
print('正在获取第{}位用户{}的用户信息...'.format(n, ut))
print("=============================================================================")
n += 1
rnum = random.randint(1, 4)
time.sleep(rnum)
res = requests.get(url, headers=headers)
html = json.loads(res.text)
if res.status_code == 200:
if not 'error' in html.keys():
# id = html['id']
# print(id)
# name = html['name']
# headline = html['headline']
print("获取成功")
print(html)
print("===================================================================")
mongo.update({'url_token': html['url_token']}, {'$set': html}, True)#update方法检查url_token字段,重复的更新,没有的添加
else:
print('未知用户')
if res.status_code == 403:
print(html['error']['redirect'])
print('data403')
indata = input('点击链接输入验证码后回车:')
# 尝试在程序运行界面直接提交验证码,但是并不成功。
# sdata = {'captcha': indata}
# sdata = json.dumps(sdata)
# u = "https://www.zhihu.com/api/v4/anticrawl/captcha_appeal"
# requests.post(u, data=sdata, headers=headers)
# time.sleep(1)
return data(ut)
def main():
start_url(url=star_follow_url)
if __name__ =='__main__':
main()
跑起来像下面这样
数据库里也能正常获取到数据
简单分析了一下里面有昵称,性别,部分用户有公司和职业信息,其他的更详细的信息,现居地,详细介绍什么的目前还不知道从哪能解析出来,留个坑以后填吧。