scrapy模拟登陆知乎--抓取热点话题

工具准备

在开始之前,请确保scrpay正确安装,手头有一款简洁而强大的浏览器, 若是你有使用postman那就更好了。

scrapy genspider zhihu

使用以上命令生成知乎爬虫,代码如下:

# -*- coding: utf-8 -*-import scrapyclassZhihuSpider(scrapy.Spider):    name ='zhihu'    allowed_domains = ['www.zhihu.com']    start_urls = ['http://www.zhihu.com/']defparse(self, response):pass

有一点切记,不要忘了启用Cookies,切记切记

# Disable cookies (enabled by default)COOKIES_ENABLED =True

模拟登陆

过程如下:

进入登录页,获取HeaderCookie信息,

完善的Header信息能尽量伪装爬虫, 有效Cookie信息能迷惑知乎服务端,使其认为当前登录非首次登录,若无有效Cookie会遭遇验证码。 在抓取数据之前,请在浏览器中登录过知乎,这样才使得Cookie是有效的。

scrapy模拟登陆知乎--抓取热点话题_第1张图片

欢迎加入我的QQ群`923414804`与我一起学习,群里有我学习过程中整理的大量学习资料。加群即可免费获取

HeaderCookie整理如下:

headers = {'Host':'www.zhihu.com','Connection':'keep-alive','Origin':'https://www.zhihu.com','User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36','Content-Type':'application/x-www-form-urlencoded; charset=UTF-8','Accept':'*/*','X-Requested-With':'XMLHttpRequest','DNT':1,'Referer':'https://www.zhihu.com/','Accept-Encoding':'gzip, deflate, br','Accept-Language':'zh-CN,zh;q=0.8,en;q=0.6',}cookies = {'d_c0':'"AHCAtu1iqAmPTped76X1ZdN0X_qAwhjdLUU=|1458699045"','__utma':'51854390.1407411155.1458699046.1458699046.1458699046.1','__utmv':'51854390.000--|3=entry_date=20160322=1','_zap':'850897bb-cba4-4d0b-8653-fd65e7578ac2','q_c1':'b7918ff9a5514d2981c30050c8c732e1|1502937247000|1491446589000','aliyungf_tc':'AQAAAHVgviiNyQsAOhSntJ5J/coWYtad','_xsrf':'b12fdca8-cb35-407a-bc4c-6b05feff37cb','l_cap_id':'"MDk0MzRjYjM4NjAwNDU0MzhlYWNlODQ3MGQzZWM0YWU=|1503382513|9af99534aa22d5db92c7f58b45f3f3c772675fed"','r_cap_id':'"M2RlNDZjN2RkNTBmNGFmNDk2ZjY4NjIzY2FmNTE4NDg=|1503382513|13370a99ee367273b71d877de17f05b2986ce0ef"','cap_id':'"NmZjODUxZjQ0NzgxNGEzNmJiOTJhOTlkMTVjNWIxMDQ=|1503382513|dba2e9c6af7f950547474f827ef440d7a2950163"',

}

在浏览器中,模拟登陆,抓取登陆请求信息。

scrapy模拟登陆知乎--抓取热点话题_第2张图片

从图中可以看到_xsrf参数, 这个参数与登陆验证信息无关,但很明显是由登陆页面携带的信息。Google了下xsrf的含义, 用于防范跨站请求伪造。

scrapy模拟登陆知乎--抓取热点话题_第3张图片


整理以上,代码如下:

loginUrl ='https://www.zhihu.com/#signin'siginUrl ='https://www.zhihu.com/login/email'defstart_requests(self):return [        scrapy.http.FormRequest(            self.loginUrl,            headers=self.headers,            cookies=self.cookies,            meta={'cookiejar':1},            callback=self.post_login)    ]defpost_login(self, response):    xsrf = response.css('div.view-signin > form > input[name=_xsrf]::attr(value)'    ).extract_first()    self.headers['X-Xsrftoken'] = xsrfreturn [        scrapy.http.FormRequest(            self.siginUrl,            method='POST',            headers=self.headers,            meta={'cookiejar': response.meta['cookiejar']},            formdata={'_xsrf': xsrf,'captcha_type':'cn','email':'[email protected]','password':'xxxxxx',

            },

            callback=self.after_login)

    ]

设置Bearer Token

经过上述步骤登陆成功了,有点小激动,有没有! 但苦难到此还远没有结束,这个时候尝试抓取最近热门话题,直接返回code:401,未授权的访问。 授权信息未设置,导致了此类错误,莫非遗漏了什么,看来只能在浏览器中追踪请求参数来侦测问题。 在浏览器的请求中,包含了Bearer Token, 而我在scrapy中模拟的请求中未包含此信息, 所以我被服务器认定为未授权的。 通过观察发现Bearer Token的关键部分,就是Cookies中的z_c0包含的信息。

scrapy模拟登陆知乎--抓取热点话题_第4张图片


z_c0包含的信息,是在登陆完成时种下的,所以从登陆完成返回的登陆信息里,获取要设置的Cookie信息, 然后拼接出Bearer Token,最后设置到Header中。

代码整理如下:

defafter_login(self, response):    jdict = json.loads(response.body)    print('after_login', jdict)if jdict['r'] ==0:        z_c0 = response.headers.getlist('Set-Cookie')[2].split(';')[0].split('=')[1]        self.headers['authorization'] ='Bearer ' + z_c0return scrapy.http.FormRequest(            url=self.feedUrl,            method='GET',            meta={'cookiejar': response.meta['cookiejar']},            headers=self.headers,            formdata={'action_feed':'True','limit':'10','action':'down','after_id': str(self.curFeedId),'desktop':'true'            },            callback=self.parse)else:        print(jdict['error'])

获取数据

上述步骤后,数据获取就水到渠成了,为了检测成功与否, 把返回信息写到文件中,而且只获取前五十个,代码如下:

feedUrl ='https://www.zhihu.com/api/v3/feed/topstory'nextFeedUrl =''curFeedId =0defparse(self, response):with open('zhihu.json','a')as fd:        fd.write(response.body)    jdict = json.loads(response.body)    jdatas = jdict['data']for entryin jdatas:        entry['pid'] = entry['id']yield entry    jpaging = jdict['paging']    self.curFeedId += len(jdatas)if jpaging['is_end'] ==Falseand self.curFeedId <50:        self.nextFeedUrl = jpaging['next']yield self.next_request(response)defnext_request(self, response):return scrapy.http.FormRequest(        url=self.nextFeedUrl,        method='GET',        meta={'cookiejar': response.meta['cookiejar']},

        headers=self.headers,

        callback=self.parse)

最终获取的数据如下图所示:

scrapy模拟登陆知乎--抓取热点话题_第5张图片

写在最后

知乎的数据,只有登录完成之后,才可有效的获取,所以模拟登陆是无法忽略不管的。 所谓的模拟登陆,只是在scrapy中尽量的模拟在浏览器中的交互过程,使服务端无感抓包过程。 请求中附加有效的CookiesHeaders头信息,可有效的迷惑服务端, 同时在交互的过程中,获取后续请求必要信息和认证信息,使得整个流程能不断先前。

你可能感兴趣的:(scrapy模拟登陆知乎--抓取热点话题)