由於課堂上大家對於如何防網站擋爬非常感興趣 這邊幫大家課後統整爬蟲防擋的小技巧 會統一在第二堂課教到如何使用 proxy 時,一併和學員示範如何實作 同時這些內容也會更新到第六屆爬蟲馬拉松,搭配不同網站的作業練習,加深學習效果 以下方法由簡單到複雜排序: (I) 發送 Request 時帶上 Headers 並切換關鍵項目 Request Headers (請求標頭)是客戶端用來告知伺服器端,客戶端這邊的瀏覽器資訊是什麼 因此模仿你在瀏覽網頁時,Network Panel 所看到的 Request Headers,也是降低網站把你判斷成爬蟲程序的機率。 import requests from fake_useragent import UserAgent # 可隨機產生 User-Agent headers = { "Accept": "*/*", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7", "Host": "https://mops.twse.com.tw", "Connection": "keep-alive", "Content-Type": "application/x-www-form-urlencoded", "Sec-GPC": 1, "User-Agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Mobile Safari/537.36", } user_agent = UserAgent() headers["User-Agent"] = user_agent.random r = requests.get(url, headers=headers) Accept-Language: 語系代碼及各個語系的權重值(詳細說明) Content-Type: 網站上的資料型態、網站會從伺服器端接收到的資料編碼格式(型態種類列表) User-Agent: 告知網站發出請求的瀏覽器的資訊 切換 User-Agent 扮演不同瀏覽器發出請求,也可以降低被伺服器判定為機器人的機率 Referer: 指定參照位址,也就是紀錄是從哪邊進到當前網頁 可以用 SEO 工具來獲取反向連結(哪個網址有連到當前頁面)當作切換池,例如下圖使用Ahrefs 獲取反向連結排名列表: (II) 設定隨機延遲時間 就是讓 sleep 的秒數從隨機整數產生,讓網站不易發現,否則頻率一致的固定模式就比較容易被偵測到是爬蟲程序在發送請求了。 import numpy as np import requests from time import sleep def fetch(url, header): sleep(np.random.randint(5, 20)) r = requests.get(url, headers=headers) return r (III) 輪流切換 IP 位址 如果同一組 IP 位址短時間內大量發送請求到目標網站,會有很大機率被網站判定為程序,因而被擋。 因此輪流切換 IP 位址是一種降低被擋機率的方式。 import requests proxies = { "http": "http://username:password@proxy_provider_host.com:20001", "https": "http://username:password@proxy_provider_host.com:20001", } r = requests.get(url, headers=headers, proxies=proxies) 其中,HTTP 及 HTTPS Proxy 間的差異如下: HTTP Proxy會從客戶端收到純文字的 Request,隨後再發送另一 Request 到目標伺服器端,最後伺服器端將資訊回傳至客戶端。 HTTPS Proxy一個中繼站的概念,會先收到客戶端一個特殊的 Request 後,與目標伺服器端建立一個不透明的通道,隨後客戶端會發送 SSL/TLS Request 到伺服器端、繼續進行 SSL 交握。 如果不確定目標網站是否需要透過 HTTPS 連線才能回傳資料,則可以在設定 requests proxies 時如上設定一個字典檔分別傳入 http, https proxy (IV) 使用 headless browser 有些網站對爬蟲的偵測比較嚴格,會檢查像是瀏覽器 Cookie 和 JavaScript 執行等,此時更建議使用 Selenium;但是預設用 Selenium 模擬瀏覽器行為時,速度會變慢很多,這時就可以用 headless 的設置,來取消網頁介面彈出,讓效能較好一些。 以下用需要 JavaScript 載入的 Pressplay 網站示範: from fake_useragent import UserAgent import numpy as np from selenium import webdriver import time # 設定 webdriver 啟動檔位址 driver_path = ( # 練習時記得換成自己的 driver path "/Users/jiunyiyang/.wdm/drivers/chromedriver/mac64/102.0.5005.61/chromedriver" ) url = "https://www.pressplay.cc/project?type=507CF74F93AD23B6584EF2C5D5D4430E" # 設定 Options opt = webdriver.ChromeOptions() user_agent = UserAgent() opt.add_argument("--user-agent=%s" % user_agent) opt.add_argument("--window-size=1920,1080") opt.add_argument("--headless") # 啟用 headless 模式 opt.add_argument("--disable-gpu") # 測試關閉 GPU 避免某些錯誤出現 # 載入目標網址 driver = webdriver.Chrome(driver_path, options=opt) driver.get(url) print(driver.title) # 模擬用戶等待網站載入,每次都用隨機時間 time.sleep(np.random.uniform(3, 5)) try: ele = driver.find_elements_by_xpath('//div[@class="project-list-item"]')[1] course = ele.find_elements_by_xpath('.//div[@id="project-card"]')[1] print(course.text) except Exception as e: print(e) finally: driver.close() print("driver closed.") 運行結果: 看到他可以成功印出那堂課程資訊卡的文字內容 P.S. 如果只用 requests 爬取就會抓不到課程區塊內的資訊卡 延伸閱讀: Python 自動化工具 – Headless Selenium 隱藏的網頁瀏覽器 (V) 其他 讓爬蟲步驟增加一些不可預測性 如果爬蟲步驟越固定,越容易被網站偵測出是程序;在使用 Selenium 時可以增加一些隨機的滾動或點擊行為,讓網站覺得你的程序越像真人的行為。 在網站流量的離峰時段爬取 如果在尖峰時段爬取,通常爬蟲程序的換頁速度比正常人瀏覽快很多,如此一來也會更明顯的拖累網站本身的效能和用戶體驗;在離峰時間爬取、並配合前面提過的隨機延時,可以避免讓伺服器超過負荷。