網絡爬蟲是一種按照必定的規則,自動地抓取網站信息的程序或者腳本。css
本文以 Python 爲例簡要談談爬蟲是如何編寫的。html
寫爬蟲以前,咱們必須確保可以爬取目標網站的信息。python
所以,先要弄清如下三個問題:mysql
一個網站假若開放了 api,那你就能夠直接 GET 到它的 json 數據。ios
好比xkcd 的 about 頁就提供了 api 供你下載git
import requests
requests.get('https://xkcd.com/614/info.0.json').json()
複製代碼
那麼如何判斷一個網站是否開放 api 呢?有 3 種方法:github
怎麼抓包:F12 - Network - F5 刷新web
實際上,app 的數據也能夠經過抓包來獲取。ajax
安裝fiddler並啓動,打開 Tools-Options-Connections,將 Allow remote computers to connect 打上勾並重啓 fiddler。sql
命令行上輸入 ipconfig,查看本身網絡的 ipv4 地址,在手機的網絡上設置 HTTP 代理,端口爲 8888。
這時雖然說能抓到數據,但都是 HTTP 的,而 app 的大部分數據都是 HTTPS 的。
在 Options-HTTPS 中將 Decrypt HTTPS traffic 打上勾。
以 ios 系統爲例,在 Safari 瀏覽器中輸入http://ipv4:8888,下載證書並安裝。
這樣就能抓到 HTTPS 數據了。
若是此網站是靜態頁面,那麼你就能夠解析它的 HTML。
解析庫強烈推薦parsel,不只語法和 css 選擇器相似,並且速度也挺快,Scrapy 用的就是它。
你須要瞭解一下css 選擇器的語法(xpath也行),而且學會看網頁的審查元素(F12 鍵)
好比獲取 konachan 的全部原圖連接
from parsel import Selector
res = requests.get('https://konachan.com/post')
tree = Selector(text=res.text)
imgs = tree.css('a.directlink::attr(href)').extract()
複製代碼
若是此網站是動態頁面,先用 selenium 來渲染 JS,再用 HTML 解析庫來解析 driver 的 page_source。
好比獲取 hitomi.la 的數據(這裏把 chrome 設置成了無頭模式)
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
driver.get('https://hitomi.la/type/gamecg-all-1.html')
tree = Selector(text=driver.page_source)
gallery_content = tree.css('.gallery-content > div')
複製代碼
目前的反爬策略常見的有:User-Agent 檢測、Referer 防盜鏈、驗證碼、登陸、封 ip 等。
前兩個最簡單:在請求的 headers 中把它們替換掉就好了
驗證碼:利用打碼平臺破解(若是硬上的話用 opencv 或 keras 訓練圖)
登陸:利用 requests 的 post 或者 selenium 模擬用戶進行模擬登錄
封 ip:買些代理 ip(免費 ip 通常都無論用),requests 中傳入 proxies 參數便可
爬蟲的結構很簡單,無非就是創造出一個 tasklist,對 tasklist 裏的每個 task 調用 crawl 函數。
大多數網頁的 url 構造都是有規律的,你只需根據它用列表推導式來構造出 tasklist
若是追求速度的話,能夠考慮用 concurrent.futures 或者 asyncio 等庫。
from pathlib import Path
from concurrent import futures
import requests
from parsel import Selector
domain = 'https://www.doutula.com'
total = []
def crawl(url):
res = requests.get(url)
tree = Selector(text=res.text)
imgs = tree.css('img.lazy::attr(data-original)').extract()
total.extend(imgs)
if __name__ == '__main__':
tasklist = [f'{domain}/article/list/?page={i}' for i in range(1, 551)]
with futures.ThreadPoolExecutor(50) as executor:
executor.map(crawl, tasklist)
Path('doutula.txt').write_text('\n'.join(total))
複製代碼
數據存儲的話,看需求,存到數據庫中的話只需熟悉對應的驅動便可。
經常使用的數據庫驅動有:pymysql(MySQL), pymongo(MongoDB)
還有一種方法就是直接利用現成的框架來編寫:looter是筆者寫的一個輕量級框架,適合中小型項目;比較大型的項目建議用scrapy。