Python爬蟲之urllib模擬登陸及cookie的那點事

在web  sprider crawl過程當中,許多網站都須要登陸後才能訪問,通常若是咱們不用爬蟲框架的前提下,常規用的就兩個庫 ,urllib庫和requests庫,本文將用最基礎的urllib庫,以模擬登陸人人網爲例,理清爬蟲過程當中登陸訪問和cookie的思緒。


 

1.終極方案,也是最簡單粗暴最有效的方式。直接手動登陸,提取cookie,下次訪問直接在請求頭攜帶cookie

       咱們知道,網站辨別用戶身份和保持會話的經常使用方式就是cookie和session,用戶登陸成功,服務器返回一些特定字符串保存在本地瀏覽器中(cookie),瀏覽器下次訪問會直接攜帶cookie,這樣服務器就能夠根據返回的cookie驗證訪問者身份。一般若是用瀏覽器正常訪問,這部分事情瀏覽器會幫咱們去作。可是在程序模擬登  錄時候,攜帶cookie就須要手動攜帶了。話很少說,直接進入主題。html

    

 

 

    打開人人網登陸界面,填入本身正確的用戶名和密碼,成功登錄進去。web

 

 

 

 

其中紅色框的就是服務器給你的cookie,你的cookie就是以這樣的形式在request請求頭中的。直接將其複製粘貼下來,放入代碼中。上程序:ajax

 

""" 首先手動登陸人人網,而後獲取cookie """

from urllib.request import urlopen, Request headers = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', # 'Accept-Encoding': 'gzip, deflate', 這部分一般註釋掉,由於這部分是高訴服務器,本地支持的壓縮類型,由於瀏覽器會自動幫咱們解壓,可是在程序中,沒辦法解壓,因此請求頭就不攜帶了
    'Accept-Language': 'zh-CN,zh;q=0.9', 'Connection': 'keep-alive', 'Cookie': 'anonymid=kcpawuyd33irh2a;depovince=GW;r01_=1; JSESSIONID=abcGzDX6FRQNVfwdUETBnx;ick_login=6a732399-3adf-471b-af92-9bd68299d515; \
    taihe_bi_sdk_uid=e4c3ee72270319312dde3088eb04c0be; taihe_bi_sdk_sefssion=6722a32d96ebbf8fd565fc7cc7f8f789;ick=1048bb79-0d32-46ab-8a11-af0c7e4cfa51;first_login_flag=1; \
    ln_uact=17795796865;ln_hurl=http://head.xiaonei.com/photos/0/0/men_main.gif; ga=GA1.2.2124318841.1594975538;gid=GA1.2.506855365.1594975538; \
    wp_fold=0;jebecookies=3833d4fe-20b3-4ecf-9efc-df9aca93641e|||||;de=5C6d0B07AA3EB53E377A21F126C928EF0; p=d3ae1effe255d4e057ef37f5682ac4850;\
    t=ba23da27a155cc2b84a43307e83b37a70;societyguester=ba23da27a155cc2b84a4f3307e83b37a70;id=974774570;xnsid=a3c6bde2;ver=7.0;loginfrom=null
', 'Host': 'www.renren.com', 'Referer': 'http://www.renren.com/974774570/profile''Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Mobile Safari/537.36' } url = 'http://www.renren.com/974774570/profile' #我的主頁 request = Request(url=url, headers=headers) response = urlopen(request) print(response.read().decode())

   註釋:程序的headers 是一個字典,是經過登陸後抓包來的以下:瀏覽器

 

 

 

 

 

 

    其實一般咱們只須要攜帶圖中的兩個參數,cookie和User-Agent,,某些get請求中,只需假裝User_agent便可。可是我爲何帶這麼多呢,那是由於,在有的網站你抓取的過程當中,你其餘參數都配置完美,可是老是抓取錯誤,那麼問題八九不離十出如今headers中,始終記住咱們是用程序模擬瀏覽器訪問服務器,說明程序假裝的還不夠完美。緩存

 那麼這時候就要考慮headers中是否缺失了某些頭部信息。爲了防止出錯,乾脆全盤端過來,反正你瀏覽器訪問的時候就是帶的這些請求頭參數。可是要注意,請求頭Accept-Encoding (程序中已經交代清楚)和 Content-Length(這是瀏覽器計算出的長度,程序模擬沒辦法計算,因此註釋掉)一般註釋掉。服務器

 

 HTTP請求中的經常使用消息頭cookie

  accept:瀏覽器經過這個頭告訴服務器,它所支持的數據類型
  Accept-Charset: 瀏覽器經過這個頭告訴服務器,它支持哪一種字符集
  Accept-Encoding:瀏覽器經過這個頭告訴服務器,支持的壓縮格式
  Accept-Language:瀏覽器經過這個頭告訴服務器,它的語言環境
  Host:瀏覽器經過這個頭告訴服務器,想訪問哪臺主機
  If-Modified-Since: 瀏覽器經過這個頭告訴服務器,緩存數據的時間
  Referer:瀏覽器經過這個頭告訴服務器,客戶機是哪一個頁面來的  防盜鏈
  Connection:瀏覽器經過這個頭告訴服務器,請求完後是斷開連接仍是何持連接session

  Content-Length:瀏覽器經過這個頭告訴服務器發出去的字節長度app

2. 模擬登陸,而後訪問主頁(在程序中咱們不須要關心cookie是如何如何的,opener對象會自動幫咱們處理,與之對應的是方式3,見下文)


 

 

 

      

 

 

 經過抓包如上圖,分析登陸post請求的地址和攜帶的參數框架

      

 

 

 直接上代碼:

"""
真正的模擬登陸是:發送post請求以後,保存cookie,以後訪問攜帶cookie
"""
# http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=2020652227884 經過這13位數,咱們能夠以男人的直覺,嗅出這是精確到毫秒的時間戳,那m咱們給他生成就是
url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp={}'  # 登陸地址
import time
from urllib.request import Request, urlopen, HTTPCookieProcessor, build_opener, ProxyHandler
from urllib.parse import urlencode
from http.cookiejar import CookieJar, MozillaCookieJar

# 1. 建立cookiejar對象,這一種方式不用手動保存cookie,後期直接調用同一個opener便可,由於cookie已經在opener對象中
cookiejar = CookieJar()

# 2.經過cookiejar建立一個handler
handler = HTTPCookieProcessor(cookiejar)
# handler1 = ProxyHandler({'http': '182.101.207.11:8080'})     # 選擇是否須要代理(本身設定代理)
# 3.根據handler建立一個opener
opener = build_opener(handler)  # build_opener以傳遞多個handler對象,若是須要代理,則將handler1也傳入
unique_time = int(time.time() * 1000)  # 生成時間戳

headers = {
    'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Mobile Safari/537.36'
}

data = {
    'email': '17795796865',
    'icode': '',
    'origURL': 'http://www.renren.com/home',
    'domain': 'renren.com',
    'key_id': '1',
    'captcha_type': 'web_login',
    # 此處密碼是通過目標網站加密,不能直接放置原生密碼,加密密碼能夠用瀏覽器抓包獲取
    'password': '4af866303efsdf40a11d9f01e9677f3374bb957f905790b62a7eaa1accaf0a634764a1',
    'rkey': '1ad002b47d8446d446f8d76f5bb5ff66',
    'f': 'http%3A%2F%2Fwww.renren.com%2F974774570%2Fnewsfeed%2Fphoto'
}
# 4 建立request對象
request = Request(url=url.format(unique_time), headers=headers)
# 5.post方式提交登陸
respose = opener.open(request, data=urlencode(data).encode())
print(respose.read().decode())
print('*' * 50)

# get方式訪問我的主頁
get_url = 'http://www.renren.com/974774570/profile'
request = Request(url=get_url, headers=headers)
respose = opener.open(request)
print(respose.read().decode())

      註釋:data中的數,咱們一個都不能少,由於post請求中,抓包能夠看到,瀏覽器就帶的這麼多參數。至於參數是什麼意思,咱們惟一能一眼看懂的就是email(用戶名)和password(密碼)。密碼是加密後的,必定不能寫原生密碼,加密後這一竄密碼能夠用瀏覽器登陸抓包獲取。至於其餘的參數,這就是爬蟲的難點,好比像大型的互聯網公司如淘寶,這裏的data參數動輒幾十個,要破解至關有難度,咱們暫且不須要關注這些,可是一般的網站咱們稍做分析大概就能猜出來這裏某個參數的意思,實在猜不出來,就原生不動的放着試着登陸。大不了登陸不進去我麼能夠採起上面的終極方案啊。始終記住,爬蟲工程師,獲取到網頁提取數據纔是你的重點。不要把精力耗費到破解form_data中的參數上。

3.手動將cookie保存到本地文件中,後續請求中直接讀取該cookie文件便可


可能有的人就有疑問了,方式2既然能模擬登陸成功,那爲何還要手動保存在本地呢,豈不是畫蛇添足。凡事存在即合理。在爬蟲過程當中,咱們能夠手動提取cookie,或者模擬登陸,可是在分佈式爬蟲或者多臺機器同時爬取時候,若是讓每臺機器都要copy cookie,或者讓每臺機器都登陸一遍,這不是明智的選擇,那麼只有事先將cookie保存在文件中,後續每臺機器的程序從文件中讀取便可。

程序和方式2的程序很類似:

import time
from fake_useragent import UserAgent
from urllib.request import Request, urlopen, HTTPCookieProcessor, build_opener, ProxyHandler
from urllib.parse import urlencode
from http.cookiejar import CookieJar, MozillaCookieJar
from time import sleep

url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp={}'


# 模擬登陸
def save_cookie():
    # 1. 建立cookiejar對象
    # cookiejar = CookieJar()  # 這一種不用保存文件中,後期直接用同一個opener對象調用就行
    cookiejar = MozillaCookieJar()  # 這種方式是將cookie保存文件中
    # 2.經過cookiejar建立一個handler
    handler = HTTPCookieProcessor(cookiejar)
    # handler1 = ProxyHandler({'http': '182.101.207.11:8080'})     # 選擇是否須要代理
    # 3.根據handler建立一個opener
    opener = build_opener(handler)  # 能夠傳遞多個handler對象,若是須要代理,則將handler1也傳入
    unique_time = int(time.time() * 1000)  # 生成時間戳

    headers = {
        'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Mobile Safari/537.36'
    }

    data = {
        'email': '17795796865',
        'icode': '',
        'origURL': 'http://www.renren.com/home',
        'domain': 'renren.com',
        'key_id': '1',
        'captcha_type': 'web_login',
        # 此處密碼是通過目標網站加密,不能直接放置原生密碼,加密密碼能夠用瀏覽器抓包獲取
        'password': '4af866303e40a11901e9677f3374bb957f905790b62a7eaa1accaf0a634764a1',
        'rkey': '1ad002b47d8446d446f8d76f5bb5ff66',
        'f': 'http%3A%2F%2Fwww.renren.com%2F974774570%2Fnewsfeed%2Fphoto'
    }

    request = Request(url=url.format(unique_time), headers=headers)
    respose = opener.open(request, data=urlencode(data).encode())
    # 建立保存能夠序列化cookie的文件對象
    cookiejar.save('cookiejar.txt', ignore_discard=True, ignore_expires=True)
    print(respose.read().decode())
    print('*' * 50)


# 訪問我的主頁
def use_cookie():
    get_url = 'http://www.renren.com/974774570/profile'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Mobile Safari/537.36'
    }
    # 1. 建立cookiejar
    cookiejar = MozillaCookieJar()
    # 2.從本地加載cookie文件
    cookiejar.load('cookiejar.txt')
    # 3.建立handler對象
    handler = HTTPCookieProcessor(cookiejar)
    # 4.建立opener對象
    opener = build_opener(handler)
    # 5.建立request對象
    request = Request(url=get_url, headers=headers)
    # 6.發送請求
    respose = opener.open(request)
    print(respose.read().decode())


if __name__ == '__main__':
    save_cookie()
    sleep(2)
    use_cookie()

運行程序咱們能夠看到本地有個cookiejar.txt文件

 

 

總結


 

   無論以哪一種方式,咱們的終極目的是爲了爬取數據,而不是花裏胡哨的模擬登錄,若是模擬登錄過程當中幾回嘗試失敗,那麼不妨能夠直接放棄,直接以第一種方式便可。畢竟人生苦短!因爲精力有限,此處就沒有涉及驗證碼,一般大多數網站登錄幾回失敗後就有驗證碼驗證。後續有機會再講。

相關文章
相關標籤/搜索