Python爬蟲(chóng)403錯(cuò)誤的終極解決方案
前言
程序使用一段時(shí)間后會(huì)遇到HTTP Error 403: Forbidden錯(cuò)誤。 因?yàn)樵诙虝r(shí)間內(nèi)直接使用Get獲取大量數(shù)據(jù),會(huì)被服務(wù)器認(rèn)為在對(duì)它進(jìn)行攻擊,所以拒絕我們的請(qǐng)求,自動(dòng)把電腦IP封了。 解決這個(gè)問(wèn)題有兩種方法。一是將請(qǐng)求加以包裝,變成瀏覽器請(qǐng)求模式,而不再是“赤裸裸”的請(qǐng)求。 但有時(shí)服務(wù)器是根據(jù)同一IP的請(qǐng)求頻率來(lái)判斷的,即使偽裝成不同瀏覽器。由于是同一IP訪問(wèn),還是會(huì)被封。 所以就有了第二種方法,就是降低請(qǐng)求頻率。具體說(shuō)來(lái)也有兩種方法。一種是在每次請(qǐng)求時(shí)暫停短暫時(shí)間,從而降低請(qǐng)求頻率。 第二種是使用不同的IP進(jìn)行訪問(wèn)。顯然第一種方法不是最佳選擇。 因?yàn)槲覀儾⒉幌M螺d太慢,尤其是在請(qǐng)求次數(shù)很多時(shí)。當(dāng)然如果間隔很短時(shí)間,從感官上并無(wú)差別,如0.1秒。 但對(duì)于服務(wù)器而言頻率就降低了很多。 所以這是一種最安全可靠的辦法,盡管我們并不想用它。第二種方法也就是使用代理IP。下面逐一介紹。
1.增加Header
在瀏覽谷歌地圖時(shí)會(huì)發(fā)現(xiàn),瀏覽了大量數(shù)據(jù)依然沒(méi)有被封IP,但程序中我們只下了幾百?gòu)埻咂?就被封了。主要原因是我們是直接Get請(qǐng)求數(shù)據(jù),而瀏覽器的請(qǐng)求是有Header的。 基于這一點(diǎn),把請(qǐng)求偽裝成瀏覽器請(qǐng)求,就可以解決這個(gè)問(wèn)題了。 代碼如下:
# coding=utf-8
import urllib2 as ulb
import numpy as np
import PIL.ImageFile as ImageFile
import cv2
import random
# 收集到的常用Header
my_headers = [
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/537.75.14",
"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0)",
'Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11',
'Opera/9.25 (Windows NT 5.1; U; en)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',
'Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.5 (like Gecko) (Kubuntu)',
'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12',
'Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/1.2.9',
"Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.7 (KHTML, like Gecko) Ubuntu/11.04 Chromium/16.0.912.77 Chrome/16.0.912.77 Safari/535.7",
"Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:10.0) Gecko/20100101 Firefox/10.0 "
]
# 獲取影像數(shù)據(jù)
def getImage(url):
# 用urllib2庫(kù)鏈接網(wǎng)絡(luò)圖像
response = ulb.Request(url)
# 隨機(jī)選擇一個(gè)Header偽裝成瀏覽器
response.add_header('User-Agent', random.choice(my_headers))
# 打開(kāi)網(wǎng)絡(luò)圖像文件句柄
fp = ulb.urlopen(response)
# 定義圖像IO
p = ImageFile.Parser()
# 開(kāi)始圖像讀取
while 1:
s = fp.read(1024)
if not s:
break
p.feed(s)
# 得到圖像
im = p.close()
# 將圖像轉(zhuǎn)換成numpy矩陣
arr = np.array(im)
# 將圖像RGB通道變成BGR通道,用于OpenCV顯示
pic = np.zeros(arr.shape, np.uint8)
pic[:, :, 0] = arr[:, :, 2]
pic[:, :, 1] = arr[:, :, 1]
pic[:, :, 2] = arr[:, :, 0]
return pic
img = getImage('https://static.fuwo.com/upload/attachment/1601/08/bea48ebeb5a811e58e9e00163e00254c.jpg')
cv2.imshow('image', img)
cv2.waitKey(0)如下所示,獲取到的網(wǎng)絡(luò)上的圖片:

但有時(shí)這樣的做法也不一定有用。前面也說(shuō)到,服務(wù)器是根據(jù)IP判斷。 給請(qǐng)求增加Header只是偽裝成不同的瀏覽器而已。如果同一個(gè)IP在短時(shí)間內(nèi)頻繁訪問(wèn), 就算是瀏覽器請(qǐng)求也會(huì)被拒絕掉。因此對(duì)于這個(gè)問(wèn)題就只好從另一個(gè)方面著手,即適當(dāng)降低單個(gè)IP訪問(wèn)頻率。 對(duì)于每個(gè)IP而言,每次請(qǐng)求操作之間都暫停一段時(shí)間。同時(shí)利用多個(gè)IP進(jìn)行訪問(wèn)。通過(guò)這兩種手段可以降低被拒絕的可能性。
2.代理IP
簡(jiǎn)單地說(shuō)是通過(guò)自動(dòng)更換不同IP來(lái)“迷惑”服務(wù)器,讓它認(rèn)為是來(lái)自不同電腦的訪問(wèn)請(qǐng)求, 從而不會(huì)被拒絕掉。由于代理IP的時(shí)效性很強(qiáng),所以需要經(jīng)常更換。最好是“現(xiàn)用現(xiàn)找”。代碼如下:
# coding=utf-8
import urllib2 as ulb
import numpy as np
import PIL.ImageFile as ImageFile
import cv2
import random
# 免費(fèi)代理IP不能保證永久有效,如果不能用可以更新
# https://www.goubanjia.com/
proxy_list = [
'183.95.80.102:8080',
'123.160.31.71:8080',
'115.231.128.79:8080',
'166.111.77.32:80',
'43.240.138.31:8080',
'218.201.98.196:3128'
]
# 獲取影像數(shù)據(jù)
def getImage(url):
# 隨機(jī)從IP列表中選擇一個(gè)IP
proxy = random.choice(proxy_list)
# 基于選擇的IP構(gòu)建連接
urlhandle = ulb.ProxyHandler({'http': proxy})
opener = ulb.build_opener(urlhandle)
ulb.install_opener(opener)
# 用urllib2庫(kù)鏈接網(wǎng)絡(luò)圖像
response = ulb.Request(url)
# 打開(kāi)網(wǎng)絡(luò)圖像文件句柄
fp = ulb.urlopen(response)
# 定義圖像IO
p = ImageFile.Parser()
# 開(kāi)始圖像讀取
while 1:
s = fp.read(1024)
if not s:
break
p.feed(s)
# 得到圖像
im = p.close()
# 將圖像轉(zhuǎn)換成numpy矩陣
arr = np.array(im)
# 將圖像RGB通道變成BGR通道,用于OpenCV顯示
pic = np.zeros(arr.shape, np.uint8)
pic[:, :, 0] = arr[:, :, 2]
pic[:, :, 1] = arr[:, :, 1]
pic[:, :, 2] = arr[:, :, 0]
return pic
img = getImage('https://mt2.google.cn/vt/lyrs=s&hl=zh-CN&gl=CN&x=214345&y=107714&z=18')
cv2.imshow('image', img)
cv2.waitKey(0)在之前由于過(guò)多使用,導(dǎo)致本機(jī)IP被封,所以無(wú)法訪問(wèn)Google地圖瓦片,出現(xiàn)如下提示。

運(yùn)行這段代碼后,就可以成功獲取瓦片,如下所示:

這樣就成功解決訪問(wèn)瓦片403問(wèn)題了。代碼列表中的IP就是在這里找的。 網(wǎng)站中還有更多付費(fèi)的高級(jí)功能,如果有需要也可以購(gòu)買(mǎi)。這里只是簡(jiǎn)單測(cè)試,就不買(mǎi)了。
3.終極方法
說(shuō)了上面兩種方法后,很自然地就會(huì)想到把兩種方法結(jié)合起來(lái)。這樣就會(huì)大大提高請(qǐng)求的種類(lèi)。 如在下面的代碼中Header有13個(gè),IP有6個(gè),排列組合就有78中請(qǐng)求。從理論上來(lái)說(shuō), 組合數(shù)越多就越不容易被封。同時(shí)再加上請(qǐng)求延遲,是較好的解決方案。
# coding=utf-8
import urllib2 as ulb
import numpy as np
import PIL.ImageFile as ImageFile
import cv2
import random
import time
# 免費(fèi)代理IP不能保證永久有效,如果不能用可以更新
# https://www.goubanjia.com/
proxy_list = [
'183.95.80.102:8080',
'123.160.31.71:8080',
'115.231.128.79:8080',
'166.111.77.32:80',
'43.240.138.31:8080',
'218.201.98.196:3128'
]
# 收集到的常用Header
my_headers = [
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/537.75.14",
"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0)",
'Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11',
'Opera/9.25 (Windows NT 5.1; U; en)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',
'Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.5 (like Gecko) (Kubuntu)',
'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12',
'Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/1.2.9',
"Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.7 (KHTML, like Gecko) Ubuntu/11.04 Chromium/16.0.912.77 Chrome/16.0.912.77 Safari/535.7",
"Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:10.0) Gecko/20100101 Firefox/10.0 "
]
# 獲取影像數(shù)據(jù)
def getImage(url):
# 設(shè)置暫停時(shí)間為0.1秒
t = 0.1
time.sleep(t)
# 隨機(jī)從列表中選擇IP、Header
proxy = random.choice(proxy_list)
header = random.choice(my_headers)
print proxy, header
# 基于選擇的IP構(gòu)建連接
urlhandle = ulb.ProxyHandler({'http': proxy})
opener = ulb.build_opener(urlhandle)
ulb.install_opener(opener)
# 用urllib2庫(kù)鏈接網(wǎng)絡(luò)圖像
response = ulb.Request(url)
# 增加Header偽裝成瀏覽器
response.add_header('User-Agent', header)
# 打開(kāi)網(wǎng)絡(luò)圖像文件句柄
fp = ulb.urlopen(response)
# 定義圖像IO
p = ImageFile.Parser()
# 開(kāi)始圖像讀取
while 1:
s = fp.read(1024)
if not s:
break
p.feed(s)
# 得到圖像
im = p.close()
# 將圖像轉(zhuǎn)換成numpy矩陣
arr = np.array(im)
# 將圖像RGB通道變成BGR通道,用于OpenCV顯示
pic = np.zeros(arr.shape, np.uint8)
pic[:, :, 0] = arr[:, :, 2]
pic[:, :, 1] = arr[:, :, 1]
pic[:, :, 2] = arr[:, :, 0]
return pic
img = getImage('https://mt2.google.cn/vt/lyrs=s&hl=zh-CN&gl=CN&x=214345&y=107714&z=18')
cv2.imshow('image', img)
cv2.waitKey(0)上述代碼中,將每一次使用的代理IP、Header都輸出到了控制臺(tái)中,利用for循環(huán)連續(xù)獲取15次。 輸出的結(jié)果如下:

在上述代碼中使用了請(qǐng)求偽裝、代理IP和請(qǐng)求延遲。 可以看到效果很好,15次請(qǐng)求都沒(méi)有被拒絕。以上這些手段只是增加了不被服務(wù)器拒絕的概率, 并不代表一定會(huì)成功。但相比于不加任何處理的請(qǐng)求,成功幾率高很多。
總結(jié)
到此這篇關(guān)于Python爬蟲(chóng)403錯(cuò)誤的終極解決方案的文章就介紹到這了,更多相關(guān)Python爬蟲(chóng)403錯(cuò)誤內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python對(duì)象轉(zhuǎn)JSON字符串的方法
這篇文章主要介紹了Python對(duì)象轉(zhuǎn)JSON字符串的方法,涉及Python基于json模塊實(shí)現(xiàn)json轉(zhuǎn)換的實(shí)現(xiàn)技巧,非常簡(jiǎn)便易懂,需要的朋友可以參考下2016-04-04
Python調(diào)用騰訊云短信服務(wù)發(fā)送手機(jī)短信
這篇文章主要為大家介紹了Python調(diào)用騰訊云短信服務(wù)發(fā)送手機(jī)短信,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
Python利用ORM控制MongoDB(MongoEngine)的步驟全紀(jì)錄
MongoEngine是一個(gè)對(duì)象文檔映射器(ODM),相當(dāng)于一個(gè)基于SQL的對(duì)象關(guān)系映射器(ORM),下面這篇文章主要給大家介紹了關(guān)于Python利用ORM控制MongoDB(MongoEngine)的相關(guān)資料,需要的朋友可以參考下2018-09-09
Python+OpenCV實(shí)現(xiàn)表面缺陷檢測(cè)
對(duì)于現(xiàn)在很多工業(yè)檢測(cè),特別是對(duì)一些精密的器件進(jìn)行篩選,往往都是像素級(jí)別的,十分的精確。本文將利用OpenCV+Python實(shí)現(xiàn)表面缺陷檢測(cè),感興趣的可以了解一下2022-08-08
python hough變換檢測(cè)直線的實(shí)現(xiàn)方法
這篇文章主要介紹了python hough變換檢測(cè)直線的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
Python程序中引用環(huán)境變量的方法實(shí)現(xiàn)
本文主要介紹了Python程序中引用環(huán)境變量的方法實(shí)現(xiàn),通過(guò)配置環(huán)境變量并在代碼中引用,可以避免將敏感信息直接寫(xiě)入代碼中,感興趣的可以了解一下2024-12-12
Python 實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)-循環(huán)隊(duì)列的操作方法
這篇文章主要介紹了Python 實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)-循環(huán)隊(duì)列的操作方法,需要的朋友可以參考下2019-07-07
使用Python將word中的圖片進(jìn)行導(dǎo)出功能
這篇文章主要為大家詳細(xì)介紹了如何使用Python將word中的圖片進(jìn)行導(dǎo)出功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-01-01
python解析Chrome瀏覽器歷史瀏覽記錄和收藏夾數(shù)據(jù)
大家好,本篇文章主要講的是python解析Chrome瀏覽器歷史瀏覽記錄和收藏夾數(shù)據(jù),感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下2022-02-02

