使用Python的POST請(qǐng)求如何使Web抓取更容易?
譯文【51CTO.com快譯】當(dāng)使用Python抓取一個(gè)網(wǎng)站時(shí),通常使用urllib或Requests庫(kù)向服務(wù)器發(fā)送GET請(qǐng)求以接收其信息。
然而,在接收所需數(shù)據(jù)之前,需要你向網(wǎng)站發(fā)送一些信息,這可能是因?yàn)楸仨殘?zhí)行登錄或以某種方式與頁(yè)面交互。
為了執(zhí)行這樣的交互,Selenium是一個(gè)常用的工具。然而,它也有一些缺點(diǎn),因?yàn)樗悬c(diǎn)慢,有時(shí)也很不穩(wěn)定。另一種方法是發(fā)送一個(gè)POST請(qǐng)求包含網(wǎng)站需要使用請(qǐng)求庫(kù)的信息。
實(shí)際上,與Requests相比,Selenium變得非常慢,是因?yàn)樗鼘?shí)際上要完成打開(kāi)瀏覽器瀏覽收集數(shù)據(jù)的網(wǎng)站的整個(gè)工作。而對(duì)于某些其他情況,POST請(qǐng)求可能是更好的選擇,這使它成為Web抓取的重要工具之一。
在本文中,將簡(jiǎn)要介紹POST方法,以及如何使用它改進(jìn)Web抓取程序。
Web 抓取
盡管POST請(qǐng)求通常用于與API交互,但它們也有助于在網(wǎng)站中填寫(xiě)HTML表單或自動(dòng)執(zhí)行其他操作。
在Web抓取過(guò)程中,能夠執(zhí)行這些任務(wù)是一項(xiàng)重要的能力,因?yàn)樵讷@取數(shù)據(jù)之前必須與Web頁(yè)面進(jìn)行交互是很常見(jiàn)的流程。
識(shí)別HTML表單
在開(kāi)始向網(wǎng)站發(fā)送信息之前,首先需要了解它將如何接收這些信息。假設(shè)你的想法是登錄你的賬戶(hù)。
如果是這種情況,您需要做的就是在POST請(qǐng)求中發(fā)送用戶(hù)名和密碼。
但是,如何識(shí)別并查看HTML表單的外觀呢?這時(shí)我們可以考慮使用我們的老朋友:GET請(qǐng)求。使用GET并使用BeautifulSoup解析HTML,很容易看到頁(yè)面上的所有HTML表單以及它們的外觀。
代碼如下所示:
import requests
from bs4 import BeautifulSoup
page = requests.get('http://website.com').text
soup = BeautifulSoup(page, 'html.parser')
forms = soup.find_all('form')
for form in forms:
print(form)
這就是我們簡(jiǎn)單的登錄表單,它將成為上面代碼的輸出:
<form action="login.html" method="post">
User Name: <input name="username" type="text"/><br/>
Password: <input name="password" type="text"/><br/>
<input id="submit" type="submit" value="Submit"/>
</form>
在這樣的表單中,“動(dòng)作”是網(wǎng)站中你應(yīng)該發(fā)送請(qǐng)求的地方,而“用戶(hù)名”和“密碼”是你想要填寫(xiě)的字段。您還可以注意到,這些值的類(lèi)型被指定為文本。
提交你的第一個(gè) POST
現(xiàn)在是發(fā)送第一個(gè)POST請(qǐng)求。基本請(qǐng)求將包含兩個(gè)參數(shù):接收請(qǐng)求的URL和發(fā)送的數(shù)據(jù)。
數(shù)據(jù)通常是一個(gè)字典,其中鍵是要填充的字段名,值是要填充的字段內(nèi)容。數(shù)據(jù)也可以通過(guò)不同的方式傳遞,但這是一種更復(fù)雜的方法,超出了本文的范圍。
代碼也非常簡(jiǎn)單,只需兩行就可以實(shí)現(xiàn):
payload = {'username': 'user', 'password': '1234'}
r = requests.post('http://website.com/login.html', data=payload)
print(r.status_code)
第三行代碼只是為了查看請(qǐng)求的狀態(tài)代碼。如果看到的狀態(tài)代碼是200,則意味著一切正常。
現(xiàn)在,我們可以通過(guò)將剛才創(chuàng)建的POST請(qǐng)求實(shí)現(xiàn)到函數(shù)中。下面是它的工作原理:
1. post_request函數(shù)將接收兩個(gè)參數(shù):URL和發(fā)送請(qǐng)求的有效負(fù)載。
2. 在函數(shù)內(nèi)部,我們將使用一個(gè) try 和 except 子句讓代碼準(zhǔn)備好處理可能的錯(cuò)誤。
3. 如果代碼沒(méi)有崩潰并且我們收到了來(lái)自服務(wù)器的響應(yīng),我們將檢查這個(gè)響應(yīng)是否是我們期望的響應(yīng)。如果是,函數(shù)將返回它。
4. 如果我們得到不同的狀態(tài)碼,將不返回任何內(nèi)容,狀態(tài)將被打印出來(lái)。
5. 如果代碼引發(fā)異常,我們希望看到發(fā)生了什么,因此該函數(shù)將打印該異常。
示例代碼如下:
def post_request(url, payload):
try:
r = requests.post(url, data=payload)
if r.status_code == 200:
return r
else:
print(r.status_code)
except Exception as e:
print(e)
然而,根據(jù)網(wǎng)站的不同,為了實(shí)際執(zhí)行登錄,還需要處理其他問(wèn)題。好消息是,Requests庫(kù)提供了處理cookie、HTTP身份驗(yàn)證等更多內(nèi)容的資源。這里的目標(biāo)只是使用一種常見(jiàn)的表單類(lèi)型作為一個(gè)簡(jiǎn)單的例子,讓未使用過(guò)POST請(qǐng)求的人能夠理解。
最后
特別是如果你向特定網(wǎng)站發(fā)送大量請(qǐng)求,你可能希望在代碼中插入一些隨機(jī)暫停,以免在整個(gè)代碼中使用更多的try和except子句使服務(wù)器過(guò)載。而不僅僅是在 post_request函數(shù)中以確保它已準(zhǔn)備好處理可能在此過(guò)程中發(fā)現(xiàn)的其他異常。
當(dāng)然,利用代理提供商來(lái)確保代碼在還需要提交請(qǐng)求和收集數(shù)據(jù)的情況下繼續(xù)運(yùn)行,以及確保連接受到保護(hù),也是一個(gè)很好的實(shí)踐。
本文的目的只是介紹POST請(qǐng)求以及它們?nèi)绾卧赪eb上收集數(shù)據(jù)。我們基本上學(xué)習(xí)了如何自動(dòng)填寫(xiě)表單,甚至如何登錄一個(gè)網(wǎng)站。
【51CTO譯稿,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文譯者和出處為51CTO.com】