最近在工作中頻繁遇到需要登錄後才能抓取的數據,但也不是沒有解決辦法,以往解決辦法如下:
A. 現在瀏覽器裏登錄,然後把登錄後的cookie粘貼到代碼中去請求,這樣就相當與利用cookie"僞造"了一個分身,從而跳過登錄驗證。
這樣往往可以解決大部分需求,但是遇到需要crontab定時爬取就顯得雞肋。cookies是有生存時間的,一旦cookies死掉那麼服務器上正在跑的代碼也會崩潰掉,如果還是用方法A的話,就需要手動的再去粘貼一個新的cookies。但是這對於一個程序員來說簡直是不能忍,一個不能自動化運行的代碼不是一個成熟的代碼(對代碼說的話:孩子,你已經長大了,是時候學會自己粘cookie了~.~)
基於以上問題,結合自己所學 得出plan B:
先用requests庫去請求登錄地址,得到response對象,然後調用response對象的 .cookies()方法 得到cookie,然後把這個cookie帶入A,然後問題解決。
# -*- coding: utf-8 -*-
import requests
userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
header = {
'Referer': 'https://account.wxb.com/from=https%3A%2F%2Fdata.wxb.com%2FrankArticle%3Fcate%3D3%26page%3D1',
'User-Agent': userAgent
}
def get_cookie():
#登錄時所請求的url(如果找不到此接口,先在瀏覽器中打開登錄界面,輸入一個錯的賬戶名密碼,點擊登錄,然後再開發者選項中就可以找到。
#爲什麼要輸入錯的呢?因爲如果正確的賬戶名密碼點擊登錄會立刻進行重定向,就找不到這個接口了)
postUrl = "https://account.wxb.com/login?from=https%3A%2F%2Fdata.wxb.com%2FrankArticle%3Fcate%3D3%26page%3D1"
#模擬登錄時帶的帳戶名,密碼
postData = {
"email": "177*****043",
"password": "weixiaobao123",
}
#發送請求,得到響應體
response=requests.post(postUrl, data=postData, headers=header,verify=False)
#返回cookie
return response.cookies()
調用此方法便可返回登錄後的cookie 注意:這個cookie是個RequestCookieJar的實例。這也是這個辦法用起來麻煩的地方
重點來了,plan C:
B中使用了response對象來返回cookie,然後每次用時需要再次設置cookies,但這樣做起來顯得很繁瑣,下面介紹一個更簡單的解決辦法。
其實解決這個問題的主要方法就是維持同一個會話,也就是相當於打開一個新的瀏覽器選項卡而不是新開一個瀏覽器。但是我又不想每次設置cookies, 那該怎麼辦呢?這時候就有了新的利器 Session對象。
利用它,我們可以方便地維護一一個會話,而且不用擔心cookies的問題,它會幫我們自動處理好。如下:
# -*- coding: utf-8 -*-
import requests, json
#注意:此get_heager方法是自己寫的一個轉換headers的方法。從網頁上複製下來的headers是字符串型,而發送請求的headers是字典類型,爲避
#免每次手動改,就索性寫了個方法自動轉換,返回字典型(懶果然是驅動進步的源泉啊 ~ ^.^)最後會送上。
from header import get_header
userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
header = {
'Referer': 'https://account.wxb.com/?from=https%3A%2F%2Fdata.wxb.com%2FrankArticle%3Fcate%3D3%26page%3D1',
'User-Agent': userAgent
}
def get_session():
postUrl = "https://account.wxb.com/login?from=https%3A%2F%2Fdata.wxb.com%2FrankArticle%3Fcate%3D3%26page%3D1"
postData = {
"email": "177*****043",
"password": "weixiaobao123",
}
#創建session對象
session = requests.session()
#使用Session對象發送登錄請求,之後cookies就已經保存在Session對象中了
session.post(postUrl, data=postData, headers=header,verify=False)
header_str = '''Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: keep-alive
Host: data.wxb.com
Referer: https://data.wxb.com/rankArticle?cate=-1&page=6
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36
X-Requested-With: XMLHttpRequest
'''
#使用get_header()方法將字符串型轉換爲可以使用的字典型
header1 = get_header(header_str)
#返回攜帶cookies的Session對象和請求頭
return session, header1
返回Session對象以後,就可以使用該對象訪問想要訪問的資源了。這是框架裏的一部分調用了此方法:
def parse(self, response):
# 得到模擬登陸後的session對象和請求頭
session, header = get_session()
for i in range(10):
url = 'https://data.wxb.com/rank/article?category=-1&page=' + str(i + 1) + '&pageSize=20&type=2&order='
res = session.get(url, headers=header, verify=False)
#將得到的數據序列化
lis = json.loads(res.text)
print(res.text)
for j in lis['data']:
item = WeixiaobaoItem()
read_num = j['read_num']
# print(read_num)
if read_num == u'10萬+':
title = j['title']
account = j['account']
index_scores = j['index_scores']
url = j['url']
like_num = j['like_num']
item['title'] = title
item['account'] = account
item['index_scores'] = index_scores
item['read_num'] = read_num
item['like_num'] = like_num
item['url'] = url
yield item
最後,把headres轉換方法以及cookies轉換方法放在這裏:
# -*- coding: utf-8 -*-
def get_header(str):
result = {} # 初始化返回結果
str_new = str.replace(': ', ':').replace(' ', '') # 第一步,將裏面的冒號空格轉換爲冒號,然後消掉tab
str_list = str_new.split('\n') # 第二部,將字符串按行分割,可能會出現列表的第一個元素和最後一個元素爲空字符串的情況
for i in str_list:
if i: # 做個篩選,過濾掉空字符串
# 此時的i是字符串,現在要將它轉爲鍵值對
temp = i.split(':')
key = temp[0]
value = ':'.join(temp[1:])
result[key] = value # 將鍵值對賦值給字典
return result
def get_cookie(str):
result = {}
str_new = str.replace(' ', '')
str_list = str_new.split(';')
for i in str_list:
if i:
temp = i.split('=')
key = temp[0]
value = ':'.join(temp[1:])
result[key] = value # 將鍵值對賦值給字典
return result
使用方法:
header_str='''Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: max-age=0
Connection: keep-alive
Host: www.baidu.com
Referer: https://www.baidu.com/s?ie=UTF-8&wd=linux%20crontab
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'''
# 返回字典
header = get_header(header_str)
cookie_str='''BIDUPSID=64C64E96A29EFCD95DBC15E7B3476840; PSTM=1527935009; BAIDUID=C5854F8A373874C0FDC858FB42BB5A3E:FG=1; __cfduid=db02ba44dd85fc27f9e77e1206c5aa4251539954648; BDUSS=hYc3hpUG1MOS16RS1TNlBTSDdSS2RwWUN1dzd5bWo2NWFrRHFOaGFvY1ZsfnRiQVFBQUFBJCQAAAAAAAAAAAEAAAC6YFstwqbKwMP0NTIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUK1FsVCtRbNU; BD_UPN=12314753; MCITY=-131%3A; BAIDUCUID=gavI8gaB28YEPvaAj8SA8juf2i0_i289_uvStguq2ii9avt_gavct_uH-t_OP2tDA; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; H_PS_PSSID=26524_1454_25810_21101_28329_28414; BD_HOME=1; delPer=0; BD_CK_SAM=1; PSINO=2; sugstore=1'''
# 返回字典
cookie= get_cookie(cookie_str)