反爬與反反爬策略
常見反爬蟲策略
知己知彼,百戰不殆。我們想防止爬蟲被 ban就得了解一些常見的反爬蟲措施。但要反爬蟲還得先識別爬蟲,所以首先講講如何識別爬蟲。
方法1:http日誌和流量分析,如果單位時間內某個IP訪問頻率和流量超過特定閾值就可以界定為爬蟲。 方法2:Headers引數檢測 Scrapy學習筆記(6)-反爬蟲與反反爬蟲策略 上圖是瀏覽器正常訪問站點時傳送的資料包,可以看到Request Headers裡面有一堆引數,目標站點可以檢測User-Agent或者Referer引數的值來判斷是否為爬蟲,順便提一下Referer引數也可以防盜鏈。 方法3:在網頁原始碼內放置一個對瀏覽器不可見的連結,正常使用者使用瀏覽器是看不到該連結的當然也不會去點選,如果檢測到該連結被點選,來訪IP就會被界定為爬蟲。 講完了爬蟲識別方法,下面開始講反爬蟲策略 1.臨時或永久封禁來訪ip 2.返回驗證碼 3.非同步載入(ajax) 4.爬蟲陷阱
常見反反爬蟲策略
針對反爬策略1可以使用高匿代理IP解決;針對反爬策略2,如果不是每次都彈驗證碼也可以使用高匿代理IP解決,如果感覺高匿代理不穩定或者收集起來不方便使用Tor網路(不懂Tor?動動你的手指百度吧_)也可以,如果每次都彈驗證碼那就得涉及到驗證碼識別了,簡單的驗證碼可以自己寫程式碼處理,python有不少知名的影象處理(識別)庫(如PIL/Pillow、Mahotas、Pymorph、pytesser、tesseract-ocr、openCV等)和演算法(比如大名鼎鼎的KNN[K鄰近演算法]和SVM[支援向量機]),但複雜的驗證碼例如涉及邏輯判斷和計算、字元粘連變形、前置噪音多色干擾、多語種字元混搭的大多也只能靠接入人工打碼平臺來對抗了;針對反爬策略3,由於採用非同步載入方式,網頁內容不會一次性全部展示出來,需要將滾動條滑到最底部才能繼續瀏覽下一頁內容,此時可以使用selenium+phantomjs解決,phantomjs是一個無頭無介面瀏覽器,使用selenium可以驅動它模擬瀏覽器的一切操作,但缺點也很明顯,爬取效率低;針對反爬策略4,看情況而定吧,如果是比較簡單的死迴圈陷阱,可以對爬蟲將要爬取的連結進行判斷,不重複爬取相同的頁面,scrapy的LinkExtractor設定unique引數為True即可或者直接設定爬蟲的最大迴圈次數。高階的陷阱筆者還沒遇到,暫不討論。此外增加爬取間隔和禁用cookie也能降低爬蟲被ban的概率。
實踐
上面說了那麼多,實踐才是硬道理,以突破IP84反爬策略為例,主要程式碼參考Scrapy學習筆記(5)-CrawlSpider+sqlalchemy實戰,下面只貼出需要修改部分的程式碼。
--coding:utf-8--
from scrapy import log import logging ‘’’ #避免被ban策略之一:使用useragent池。 使用注意:需在settings.py中進行相應的設定。 ‘’’ import random from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware class UserAgent(UserAgentMiddleware):
def __init__(self, user_agent=''): self.user_agent = user_agent def process_request(self, request, spider): ua = random.choice(self.user_agent_list) if ua: #顯示當前使用的useragent #print "********Current UserAgent:%s************" %ua #記錄 log.msg('Current UserAgent: '+ua, level=logging.DEBUG) request.headers.setdefault('User-Agent', ua) #the default user_agent_list composes chrome,I E,firefox,Mozilla,opera,netscape #for more user agent strings,you can find it in http://www.useragentstring.com/pages/useragentstring.php user_agent_list = [\ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 " "(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1", "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 " "(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 " "(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 " "(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 " "(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 " "(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5", "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 " "(KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 " "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 " "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24" ]
import random, base64
class ProxyMiddleware(object):
#代理IP列表
proxyList = [ \
'114.231.158.79:8088',
'123.233.153.151:8118'
]
def process_request(self, request, spider):
# Set the location of the proxy
pro_adr = random.choice(self.proxyList)
print "USE PROXY -> " + pro_adr
request.meta['proxy'] = "http://" + pro_adr
BOT_NAME = 'ip_proxy_pool'
SPIDER_MODULES = ['ip_proxy_pool.spiders']
NEWSPIDER_MODULE = 'ip_proxy_pool.spiders'
#Obey robots.txt rules
ROBOTSTXT_OBEY = False
ITEM_PIPELINES = {
'ip_proxy_pool.pipelines.IpProxyPoolPipeline': 300,
}
#爬取間隔
DOWNLOAD_DELAY = 1
#禁用cookie
COOKIES_ENABLED = False
#重寫預設請求頭
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html, application/xhtml+xml, application/xml',
'Accept-Language': 'zh-CN,zh;q=0.8',
'Host':'ip84.com',
'Referer':'http://ip84.com/',
'X-XHR-Referer':'http://ip84.com/'
}
#啟用自定義UserAgent和代理IP
#See http://scrapy.readthedocs.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
'ip_proxy_pool.useragent.UserAgent': 1,
'ip_proxy_pool.proxymiddlewares.ProxyMiddleware':100,
'scrapy.downloadermiddleware.useragent.UserAgentMiddleware' : None,
}
4.開始爬取,發現已經能正常運行了。