摘要:這里不討論用的情況,僅僅以來說明模擬登陸先嘗試用真實(shí)瀏覽器登陸,登陸成功后在開發(fā)者工具的選項(xiàng)卡中捕獲文件。
這里不討論用 Github API 的情況,僅僅以 Github 來說明模擬登陸
先嘗試用真實(shí)瀏覽器登陸,登陸成功后在開發(fā)者工具的 Network 選項(xiàng)卡中捕獲 Session 文件??梢钥吹?,登陸所需要的數(shù)據(jù)不僅僅是 email(或用戶名) 和密碼,還需要其它的 3 個(gè)字段,而這 3 個(gè)字段普通用戶在真實(shí)瀏覽器中是無法填寫的(也無需填寫,這仨字段會(huì)自動(dòng)附加到表單中提交)。
其中的 commit、utf8 的值是不變的,只有 authenticity_token 字段的值是每次登陸都不一樣的(為的就是區(qū)分人類與爬蟲程序),authenticity_token 字段是在 https://github.com/login (登陸頁面,未登陸狀態(tài))的 from 元素下的一個(gè)隱含字段(不顯示在瀏覽器中),其 type 屬性值為 hidden。
下圖展示了(重新)登陸頁面的源碼,其中 type 屬性為 hidden 的 input 字段中的 authenticity_token 屬性的值就是需要提取出來作為表單數(shù)據(jù)的一部分提交至服務(wù)器
從下圖可以看到響應(yīng)碼(Status Code)是 302 found 表示重定向跳轉(zhuǎn)至其它 url,這里跳轉(zhuǎn)至 https://github.com,也就是說,登陸成功后就跳轉(zhuǎn)至 Github 首頁(即個(gè)人主頁)
雖然是在 https://github.com/login 頁面中登陸,但登陸時(shí)是向 https://github.com/session 提交表單數(shù)據(jù),所以在 session 響應(yīng)中可惜查看到已提交的表單數(shù)據(jù)。
上圖展示了登陸成功后,已提交的表單數(shù)據(jù),可以發(fā)現(xiàn) authenticity_token 字段的值和登陸前的值是一致的(email、password 字段由于是明文,所以這里打碼了)
能保持登陸狀態(tài)的原因是登陸成功后生成 Cookies 的功勞,不過 Cookies 一般不是永久有效的,如果希望長(zhǎng)期處于登陸狀態(tài),需要每隔一段時(shí)間檢測(cè)下 Cookies 是否還有效(或進(jìn)行異常處理),失效的話就需要重新提交表單生成新的 Cookies。
代碼實(shí)現(xiàn)使用的庫(kù)
requests
pyquery
攜帶 Cookies 模擬登陸 Github 的例子代碼中的表單數(shù)據(jù) post_data 的 login、password 這倆字段分別需要改為自已的 email(或用戶名)及密碼
import requests from pyquery import PyQuery as pq headers = { "Referer": "https://github.com/", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", "Host": "github.com", } login_url = "https://github.com/login" post_url = "https://github.com/session" logined_url = "https://github.com/settings/profile" keys_url = "https://github.com/settings/keys" # 提取隱含字段 authenticity_token 的值,登陸需要提交表單,而提交表單需要該值 login_r = requests.get(login_url, headers=headers) doc = pq(login_r.text) token = doc("input[name="authenticity_token"]").attr("value").strip() print(token) # 構(gòu)造表單數(shù)據(jù) post_data = { "commit": "Sign in", "utf8": "?", "authenticity_token": token, "login": email_or_name, "password": password, } # 模擬登陸必須攜帶 Cookies post_r = requests.post(post_url, data=post_data, headers=headers, cookies=login_r.cookies.get_dict()) # 可以發(fā)現(xiàn)響應(yīng)的 url 是 https://github.com,而不是 https://github.com/session # 因?yàn)槟M登陸成功后就 302 重定向跳轉(zhuǎn)至 "https://github.com" 了 print(post_r.url) doc = pq(post_r.text) # 輸出項(xiàng)目列表 print(doc("div.Box-body > ul > li").text().split()) # 請(qǐng)求其它 github 頁面,只要附加了能維持登陸狀態(tài)的 Cooikes 就可以訪問只有登陸才可訪問的頁面內(nèi)容 logined_r = requests.get(logined_url, headers=headers, cookies=post_r.cookies.get_dict()) doc = pq(logined_r.text) page_title = doc("title").text() user_profile_bio = doc("#user_profile_bio").text() user_profile_company = doc("#user_profile_company").attr("value") user_profile_location = doc("#user_profile_location").attr("value") print(f"頁面標(biāo)題:{page_title}") print(f"用戶資料描述:{user_profile_bio}") print(f"用戶資料公司:{user_profile_company}") print(f"用戶資料地點(diǎn):{user_profile_location}") # 使用 logined_r 的 Cookies 也可以 keys_r = requests.get(keys_url, headers=headers, cookies=post_r.cookies.get_dict()) doc = pq(keys_r.text) # SSH keys Title doc("#ssh-key-29454773 strong.d-block").text()
顯式傳入 Cookies 、headers 還是挺麻煩的,萬一有個(gè)請(qǐng)求沒有攜帶完整的 Cookies,可能就無法得到正確的響應(yīng)。
為了省略每次都要手動(dòng)傳入 Cookies 的麻煩,下面使用另一種方式模擬登陸 Github
利用 Session 對(duì)象維持 Github 模擬登陸狀態(tài)構(gòu)造一個(gè) session 對(duì)象;
使用 session 對(duì)象進(jìn)行請(qǐng)求
代碼其中使用 session.headers 維持每次會(huì)話的 headers 不變
為了安全,利用內(nèi)置模塊 getpass 輸入不可見的密碼(注意密碼一定不能錯(cuò))
import getpass import requests from pyquery import PyQuery as pq class Login(object): def __init__(self): base_url = "https://github.com/" # 登陸 url self.login_url = base_url +"login" # 提交表單的 api self.post_url = base_url +"session" # 個(gè)人資料頁面的 url self.logined_url = base_url +"settings/profile" # 構(gòu)造一個(gè)會(huì)話對(duì)象 self.session = requests.Session() # 自定義請(qǐng)求頭 self.session.headers = { "Referer": "https://github.com/", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", "Host": "github.com" } def token(self): # 請(qǐng)求登陸頁面 response = self.session.get(self.login_url) # 提取 authenticity_token 的 value, doc = pq(response.text) token = doc("input[name="authenticity_token"]").attr("value").strip() return token def login(self, email, password): token = self.token() # 構(gòu)造表單數(shù)據(jù) post_data = { "commit": "Sign in", "utf8": "?", "authenticity_token": token, "login": email, "password": password } # 發(fā)送 POST 請(qǐng)求,它會(huì) 302 重定向至 "https://github.com/",也就是響應(yīng) "https://github.com/" 的頁面 response = self.session.post(self.post_url, data=post_data) # 可以發(fā)現(xiàn) 302 重定向至 "https://github.com/" print(f" 請(qǐng)求 url:{response.url}") if response.status_code == 200: print("status_code: 200") self.home(response.text) # 請(qǐng)求個(gè)人資料頁 response = self.session.get(self.logined_url) if response.status_code == 200: print("status_code: 200") self.profile(response.text) def home(self, html): doc = pq(html) # 提取用戶名 user_name = doc("summary > span").text().strip() print(f"用戶名:{user_name}") # 提取倉(cāng)庫(kù)列表 Repositories = doc("div.Box-body > ul > li").text().split() for Repositorie in Repositories: print(Repositorie) def profile(self, html): doc = pq(html) page_title = doc("title").text() user_profile_bio = doc("#user_profile_bio").text() user_profile_company = doc("#user_profile_company").attr("value") user_profile_location = doc("#user_profile_location").attr("value") print(f"頁面標(biāo)題:{page_title}") print(f"用戶資料描述:{user_profile_bio}") print(f"用戶資料公司:{user_profile_company}") print(f"用戶資料地點(diǎn):{user_profile_location}") def main(self): email = input("email or username: ") # 輸入的密碼不可見,注意密碼一定不能錯(cuò) password = getpass.getpass("password:") self.login(email=email, password=password) if __name__ == "__main__": login = Login() login.main()
本文參考 《Python 3 網(wǎng)絡(luò)爬蟲開發(fā)實(shí)戰(zhàn)》 —— 10.1 模擬登陸并爬取 GitHub
隱含字段參考了 《Python網(wǎng)絡(luò)數(shù)據(jù)采集》 —— 12.3 常見表單安全措施
閱讀更多字符圖像識(shí)別——數(shù)字字母混合
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/42266.html
摘要:微信知乎新浪等主流網(wǎng)站的模擬登陸爬取方法摘要微信知乎新浪等主流網(wǎng)站的模擬登陸爬取方法。先說說很難爬的知乎,假如我們想爬取知乎主頁的內(nèi)容,就必須要先登陸才能爬,不然看不到這個(gè)界面。圖片描述知乎需要手機(jī)號(hào)才能注冊(cè)登陸。 微信、知乎、新浪等主流網(wǎng)站的模擬登陸爬取方法摘要:微信、知乎、新浪等主流網(wǎng)站的模擬登陸爬取方法。 網(wǎng)絡(luò)上有形形色色的網(wǎng)站,不同類型的網(wǎng)站爬蟲策略不同,難易程度也不一樣。從是...
摘要:可能有的老手覺得我寫得很啰嗦,但其實(shí)很多新手可能都不知道這些細(xì)節(jié),所以我把我在分析新浪微博模擬登陸的過程全寫了出來。 這篇文章于去年4月發(fā)布在我的簡(jiǎn)書,現(xiàn)在把它放到這里,主要是為了宣傳自己的分布式微博爬蟲。下面是主要內(nèi)容,希望能幫到有這個(gè)需求的朋友 最近由于需要一直在研究微博的爬蟲,第一步便是模擬登陸,從開始摸索到走通模擬登陸這條路其實(shí)還是挺艱難的,需要一定的經(jīng)驗(yàn),為了讓朋友們以后少...
摘要:在抓取數(shù)據(jù)之前,請(qǐng)?jiān)跒g覽器中登錄過知乎,這樣才使得是有效的。所謂的模擬登陸,只是在中盡量的模擬在瀏覽器中的交互過程,使服務(wù)端無感抓包過程。若是幫你解決了問題,或者給了你啟發(fā),不要吝嗇給加一星。 折騰了將近兩天,中間數(shù)次想要放棄,還好硬著頭皮搞下去了,在此分享出來,希望有同等需求的各位能少走一些彎路。 源碼放在了github上, 歡迎前往查看。 若是幫你解決了問題,或者給了你啟發(fā),不要吝...
摘要:我們這次模擬登陸成功的標(biāo)志就是拿到登陸后的和,有過期時(shí)間,我稍微測(cè)試了下大概有個(gè)小時(shí)左右。因?yàn)槲⑿殴娖脚_(tái)老是跳轉(zhuǎn)刷新,所以很難找到請(qǐng)求的網(wǎng)址和接口。分析結(jié)果的過程不難,照著登陸流程走,反復(fù)調(diào)試就可以。 聲明此代碼僅供技術(shù)交流學(xué)習(xí),擅自用于其他,一切后果與本人無關(guān) 目標(biāo)網(wǎng)址: https://mp.weixin.qq.com/ 所謂模擬登陸,就是自己模擬構(gòu)造請(qǐng)求發(fā)送給服務(wù)器,然后服務(wù)器...
摘要:大致意思是模擬登陸,一時(shí)手癢,本文將帶領(lǐng)大家一起實(shí)現(xiàn)這個(gè)操作。方案事實(shí)上為了探究這個(gè)有意思的問題,我專門動(dòng)手做一個(gè)有意思的實(shí)驗(yàn)。這說明了服務(wù)端驗(yàn)證了輸入,并判斷我們的請(qǐng)求不符合正常邏輯。過程不再贅述,結(jié)果是中的必須和中的對(duì)應(yīng)。 前言 本文來自我在 SegmentFault 上的 回答,我紀(jì)錄了其中精彩的部分到本博客。 大致意思是模擬登陸 segmentfault.com,一時(shí)手癢,本文...
閱讀 3623·2021-11-24 10:25
閱讀 2549·2021-11-24 09:38
閱讀 1238·2021-09-08 10:41
閱讀 2921·2021-09-01 10:42
閱讀 2603·2021-07-25 21:37
閱讀 1997·2019-08-30 15:56
閱讀 928·2019-08-30 15:55
閱讀 2765·2019-08-30 15:54