1. 程式人生 > >scrapy突破反爬的幾種方式(二)

scrapy突破反爬的幾種方式(二)

上回說到設定隨機 User-Agent ,這次來一個隨機代理 ip 的設定。

代理ip

在爬蟲中,為了避免網站將我們的 ip 封掉,我們就要使用代理 ip 。雖然說代理 ip 沒有原裝的好,但是有些時候還是要使用代理ip 來獲取資料的。

原理

隨機代理 ip 簡單來說就是爬取網上的免費代理ip ,然後存入資料庫,在資料庫中隨機拿到一個代理ip來用。具體結合到 scrapy 中,我們就要在 Middleware.py 檔案中修改,原理跟上文代理的設定一樣,不懂的可以去上篇文章看一下。

實戰演練

在上文的 scrapydownloadertest 專案基礎上操作。 在 spiders 的同級目錄下,新建一個 Python Package 。還要新建python檔案,具體名稱參考圖片。目錄結構如下:

目錄結構

目錄結構

從西刺網上獲取免費的代理ip 儲存到資料庫中。

import requests
from scrapy.selector import Selector
import pymysql

# 連線資料庫
conn = pymysql.connect(host='',user='',password='',db='proxy',charset='utf8')
cursor = conn.cursor()
# 爬取西刺網站上的代理ip

def crawler_ips():
    headers = {
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
    }
    for i in range(100):
        url = 'http://www.xicidaili.com/nn/'.format(i)
        r = requests.get(url,headers=headers)
        selector = Selector(text=r.text)
        all_ips = selector.css('#ip_list tr')
        ip_list = []
        for tr in all_ips[1:]: # 這裡由於第一個是標題,捨棄
            speed_str = tr.css('.bar::attr(title)').extract_first()[0]
            if speed_str:
                speed = float(speed_str.split('秒')[0])
            all_texts = tr.css('td::text').extract()

            ip = all_texts[0]
            port = all_texts[1]
            proxy_type = all_texts[5]

            ip_list.append((ip,port,proxy_type,speed))

        for ip_info in ip_list:
            # 插入資料
            cursor.execute(
                "insert proxy_ip(ip,port,speed,proxy_type) VALUES('{0}','{1}',{2},'HTTP')".format(
                ip_info[0],ip_info[1],ip_info[3]
                )
            )
            conn.commit()

資料庫我用的是MySQL,在 navivat for mysql 中連線 MySQL ,新建一個數據庫,名稱隨意,這裡就叫做 proxy 吧,在程式碼中把連線資料庫的程式碼補充完整。 新建一個數據表 proxy_ip 並寫下如下欄位:

proxy_ip

proxy_ip

這裡我已經新建好了,並且執行的程式碼。

新建之後,我們執行上述程式碼,這時候會看到資料庫中已經有了資料。接下來就是從資料庫中隨機獲取一個代理 ip ,供我們程式使用。

class GetIP(object):
    def get_random_ip(self):
        # 從資料庫中隨機獲取一個可用ip
        random_sql = 'SELECT ip,port FROM proxy_ip ORDER BY RAND() LIMIT 1'
        result = cursor.execute(random_sql)
        for ip_info in cursor.fetchall():
            ip = ip_info[0]
            port = ip_info[1]
            judge_re = self.judge_ip(ip,port)
            if judge_re:
                return 'http://{0}:{1}'.format(ip,port)
            else:
                return self.get_random_ip()

    def judge_ip(self,ip,port):
        # 判斷ip 是否可用
        http_url = 'http://www.baidu.com'
        proxy_url = 'http://{0}:{1}'.format(ip,port)
        try:
            proxy_dict = {
                'http':proxy_url
            }
            r = requests.get(http_url,proxies=proxy_dict)
            print('effective ip')
            return True
        except Exception as e:
            print('invalid ip and port 無效')
            self.delete_ip(ip)
            return False
        else:
            code = r.status_code
            if code >= 200 and code < 300:
                print('effective ip')
                return True
            else:
                print('invalid ip and port 無效')
                self_delete_ip(ip)
                return False


    def delete_ip(self,ip):
        # 刪除無效的ip
        delete_sql = "delete from proxy_ip where ip = '{0}'".format(ip)
        cursor.execute(delete_sql)
        conn.commit()

if __name__ == '__main__':
    get_ip = GetIP()
    print(get_ip.get_random_ip())

這裡從資料庫中隨機獲取一個代理ip,並測試代理ip是否可用,不可用的刪掉。這裡有個小技巧,如果你爬取的是其他網站,就把百度的連結換成你要爬取的網站,這樣會提高代理ip的可用性。 執行此程式碼會隨機獲取一個可用的ip代理。

接下來在 Middleware.py 中把代理ip 加上:

class RandomProxyMiddleware(object):
    # 動態設定ip代理
    def process_request(self, request, spider):
        get_ip = GetIP()

        request.meta['proxy'] = get_ip.get_random_ip()

在 settings.py 檔案中配置一下:

DOWNLOADER_MIDDLEWARES = {
    'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware': None,
    'scrapydownloadertest.middlewares.RandomUserAgentMiddleware': 543,
    'scrapydownloadertest.middlewares.RandomProxyMiddleware': 544,

}

執行spider檔案,就可以在輸出的日誌上面看到代理ip在使用了。

2018-09-16 16:57:46 [urllib3.connectionpool] DEBUG: http://123.249.88.153:9000 "GET http://www.baidu.com/ HTTP/1.1" 200 None
effective ip

總結

  • 使用這樣的方法可以用到代理 ip 從而有效的隱藏了自己的真實 ip 。免費從網上獲取的代理通常來說沒有付費得到的 ip 穩定性好。如果有條件,還是建議自費獲取一些代理 ip。

  • 自己的代理還是最好用的,我們在爬取的時候可以放慢速度,增加延遲等方式以避免自己的 ip 被封。同時不要讓網站的壓力太大。這樣才能共存。