1. 程式人生 > >應對反爬蟲問題(正在學習中)

應對反爬蟲問題(正在學習中)

1.構造合理的HTTP請求頭

目前我一般使用的是更改User-Agent 有些網站不喜歡爬蟲訪問,會檢測連線物件,如果是爬蟲程式不會讓你訪問

import requests
url='https://www.amazon.cn/'
hd={'User-Agent':'Mozilla/5.0'}
try:
    r=requests.get(url,headers=hd)
    r.raise_for_status()
    print(r.request.headers)
except:
    print('----')


#輸出
{'User-Agent': 'Mozilla/5.0'
, 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}

2.注意隱含輸入欄位

在 HTML 表單中,“隱含”欄位可以讓欄位的值對瀏覽器可見,但是對使用者不可見(除非看網頁原始碼)。

用隱含欄位阻止網路資料採集的方式主要有兩種。 第一種是表單頁面上的一個欄位可以用伺服器生成的隨機變量表示。如果提交時這個值不在表單處理頁面上,伺服器就有理由認為這個提交不是從原始表單頁面上提交的,而是由一個網路機器人直接提交到表單處理頁面的。繞開這個問題的最佳方法就是,首先採集表單所在頁面上生成的隨機變數,然後再提交到表單處理頁面。

第二種方式是“蜜罐”(honey pot)。如果表單裡包含一個具有普通名稱的隱含欄位(設定蜜罐圈套),比如“使用者名稱”(username)或“郵箱地址”(email address),設計不太好的網路機器人往往不管這個欄位是不是對使用者可見,直接填寫這個欄位並向伺服器提交,這樣就會中伺服器的蜜罐圈套。伺服器會把所有隱含欄位的真實值(或者與表單提交頁面的預設值不同的值)都忽略,而且填寫隱含欄位的訪問使用者也可能被網站封殺。

那麼該如何去避開蜜罐圈套

比如我們在進行網路爬蟲的時候,我們很容易可以採集到資訊,但是如果爬取到的一個網路表單的欄位通過CSS設定成不可見,那麼普通使用者在瀏覽器上是看不的,所以也不可能填寫這個欄位,如果被被填寫了,就會認為可能是爬蟲乾的,那麼就是封禁你。

這種手段不僅可以應用在網站的表單上,還可以應用在連結、圖片、檔案,以及一些可以被機器人讀取,但普通使用者在瀏覽器上卻看不到的任何內容上面。訪問者如果訪問了網站上的一個“隱含”內容,就會觸發伺服器指令碼封殺這個使用者的 IP 地址,把這個使用者踢出網站,或者採取其他措施禁止這個使用者接入網站。

from selenium import webdriver
url='http://pythonscraping.com/pages/itsatrap.html'
driver=webdriver.Chrome()
driver.get(url)
items=driver.find_elements_by_tag_name('a')
for item in items:
    if not item.is_displayed():#如果標籤是不可見的
        print('{}連結不可見'.format(item.get_attribute('href')))
inputs=driver.find_elements_by_tag_name('input')
for item in inputs:
    if not item.is_displayed():
        print('{}此表單不可填寫'.format(item.get_attribute('name')))



#輸出
http://pythonscraping.com/dontgohere連結不可見
phone此表單不可填寫
email此表單不可填寫

3.建立自己的代理IP池

伺服器會檢測一個IP在單位時間內的請求次數,如果超過了某個閾值,那麼伺服器會直接拒絕服務,返回一些錯誤資訊。 所以我們可以藉助某種方式來偽裝IP,讓伺服器無法識由我們本機發起的請求,這樣子我們就可以防止封IP了

這裡我們需要 1.去網站爬取免費的IP 2.檢查爬去的IP是否有效 3.將有效的IP儲存下來

那麼怎麼樣才能檢測一個IP是否有效呢? 第一種方式:利用requests.get(url,timeout=?),設定timeout一個值,超時了就說明不可用 第二種方式:用本機去ping這個IP,如果ping通,那麼就說明這個IP也能去訪問其他的網址

我利用第二種方式去實現 那麼怎麼利用python實現 Subprocess.Popen()可以建立一個程序,當shell引數為true時,程式通過shell來執行:

引數: 這裡寫圖片描述

程式碼:

from bs4 import BeautifulSoup
import requests
import subprocess as sp
import re


def getIP(IPlist):  # 爬取網頁上的免費ip,並且存入IPlist
    url = 'http://www.xicidaili.com/nn'  # 獲得免費IP的網址
    hd = {'User-Agent': 'Mozilla/5.0'}  # 模擬瀏覽器進行訪問
    try:
        r = requests.get(url, headers=hd)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        soup = BeautifulSoup(r.text, 'html.parser')
        # 根據頁面結構來選擇出元素
        list = (soup.select('tr')[1:])  # 用CSS選擇器先找到tr標籤,其中第一個標籤是無效的
        for item in list:  # 遍歷
            taglist = item.select('td')  # 找到td標籤,其中第二,第三,第五個標籤是我們想要的
            ip = taglist[5].string.lower() + '#' + taglist[1].string + '#' + taglist[2].string  # 新增#後面好處理
            IPlist.append(ip)
    except:
        print('1111')


def check_ip(ip):  # 檢查ip是否可用
    cmd = 'ping -n 3 -w 3 {}'.format(ip)  # 本機能夠ping通這個代理IP,那麼我們也就可以使用這個代理IP去訪問其他網站
    p = sp.Popen(cmd, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, shell=True)  # 使用Subprocess.Popen可以建立一個程序
    out = p.stdout.read().decode('gbk')
    # 丟包數
    Lost_Packets = loss(out)
    # 平均耗時
    time = average_time(out)
    # 選擇出可用的ip,可用就返回True
    if Lost_Packets <= 1 and time <= 500:  # 當丟包數小於1,平均耗時小於500ms
        return True
    else:
        return False


def loss(out):  # 匹配出丟包數
    match = re.search(r'丟失 = (\d)', out)  # 利用正則表示式
    Lost_Packets = int(match.group(1))
    return Lost_Packets


def average_time(out):
    match2 = re.search(r'平均 = (\d*)ms', out)
    if match2:
        return int(match2.group(1))
    else:
        return 1000


def main():
    IPlist = []
    getIP(IPlist)
    ulist = []  # 用來儲存可用的IP地址
    for IP in IPlist:  # 先檢查前20個
        elements = IP.split('#')  # 以'#'分割,提取其中的關鍵資訊
        ip = elements[1]
        # print(ip)
        if check_ip(ip):
            ulist.append({elements[0]: elements[1] + ':' + elements[2]})
    print(ulist)
main()


#給出部分輸出
{'http': '111.194.14.157:8118'}, {'https': '106.14.47.5:80'}, {'http': '106.75.225.83:808'}, {'https': '218.59.228.18:61976'}

這樣就好啦 以後學習到其他的繼續更新