寫腳本從指定網站抓取數據的時候,免不了會被網站屏蔽IP。所以呢,就需要有一些IP代理。隨便在網上找了一個提供免費IP的網站西刺做IP抓取。本次實踐抓取的是其提供的國內匿名代理。可以打開網站查看一下源碼,我們需要的內容在一個table區域內,通過BS4能很容易提取需要的信息。
Step 1:HTML頁面獲取
觀察可以發現有我們需要的信息的頁面url有下面的規律:www.xicidaili.com/nn/
+頁碼
。可是你如果直接通過get方法訪問的話你會發現會出現500錯誤。原因其實出在這個規律下的url雖然都是get方法獲得數據,但都有cookie認證。那么問題來了——怎么獲得需要的cookie呢?
我們可以想一下,我們第一次通過瀏覽器訪問該網站的主頁是能打開的,其網站的各個子模塊都可以打開。一定在某個時間段內我們的瀏覽器獲得了該網站設置的cookie。清楚瀏覽器cookie,重新打開該網站首頁,通過開發者工具可以發現我們打開首頁的時候沒有上傳cookie,而是網站會下發cookie。接着打開我們上面找到的規律url頁面,比對一下,發現我們上傳的cookie就是在首頁下發的cookie。這樣就有辦法了——編寫腳本的時候,先訪問一下首頁獲得cookie,再將獲得的cookie添加到后續的請求中。
具體的代碼如下:
import time
import json
import requests
from bs4 import BeautifulSoup
_headers={
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding":"gzip, deflate, sdch",
"Accept-Language":"zh-CN,zh;q=0.8",
"Cache-Control":"max-age=0",
"Host":"www.xicidaili.com",
"Referer":"http://www.xicidaili.com/nn/",
"Upgrade-Insecure-Requests":"1",
"User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36"
}
_cookies = None
def spider(total_page):
url = "http://www.xicidaili.com/nn/"
for i in range(1,total_page):
if i % 100 == 0:
#100個頁面更新一次Cookie
_cookies = requests.get("http://www.xicidaili.com/",headers=_headers).cookies
r = requests.get(url+str(i),headers = _headers,cookies = _cookies)
html_doc = r.text
#print html_doc
status_code = r.status_code
print i,status_code
r.close()
with open("%s.html"%i,"w") as f: #保存html,也可以直接信息提取
f.write(html_doc.encode("utf-8"))
time.sleep(1)
_headers["Referer"]=url+str(i-1)
if __name__ == "__main__":
_cookies = requests.get("http://www.xicidaili.com/",headers=_headers).cookies
spider(200)
Step2 : 信息提取
分析html結構,使用BS4進行信息提取。具體代碼如下:
from bs4 import BeautifulSoup
#import re
def parese(html_doc):
ip_info = []
soup = BeautifulSoup(html_doc,"lxml")
for tag in soup.find_all(name = "table"):#,class_="odd"):#),attrs={"data-foo": "value"}):
for tr in tag.find_all("tr",class_=True)#class_=True <=> re.compile("odd|")
try:
tmp = tr.find_all("td",class_=None):
ip = tmp[0].string
port = tmp[1].string
except:
pass
ip_info.append(zip(ip,port))
return ip_info