[Python]公式轉圖片程序的反爬蟲改進

上一篇我們已經按照思路實現了基礎功能,實現公式和圖片的自動轉換。

但是大家在使用的時候會發現,跑着跑着 就斷掉了!報錯了啊!丟失連接之類的。倖幸苦苦的抓了半天又得從頭來,心累啊!
這就是網站的反爬蟲在起作用了,一個IP訪問次數過於頻繁就先將這個IP加入黑名單,過一會兒再放出來。雖然不影響正常使用但是對於爬蟲來說很致命啊!因爲爬蟲會報錯退出啊!然後我們又得重來。
一般來說我們會遇到網站反爬蟲策略下面幾點:

  • 後臺對訪問進行統計,如果單個userAgent訪問超過閾值,予以封鎖。(效果出奇的棒!不過誤傷也超級大,一般站點不會使用,不過我們也考慮進去
  • 限制IP訪問頻率,超過頻率就斷開連接。(這種方法解決辦法就是,降低爬蟲的速度在每個請求前面加上time.sleep;或者不停的更換代理IP,這樣就繞過反爬蟲機制啦!)
  • 還有針對於cookies的 (這個解決辦法更簡單,一般網站不會用)
    我們今天就來針對1、2兩點來寫個下載模塊、別害怕真的很簡單。

繼續通過模仿來解決這個問題,繼續在網上找大神寫的博客https://cuiqingcai.com/3256.html「靜覓丨崔慶才的個人博客」,看看人家是怎麼做的。

首先我們修改User-Agent,這個參數是用來僞裝成瀏覽器的,多寫幾個,就可以假裝是不同瀏覽器在訪問頁面
搜索關鍵字 「User-Agent list」就可以得到了

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"
    ]
UA = random.choice(user_agent_list)#隨機一個瀏覽器User-Agent
headers = {'User-Agent': UA}
start_html = requests.post(all_url,headers=headers)

這個思路非常清晰吧,就是每次使用的headers是隨機得到的,這樣第一個反爬蟲手段就被我們解決了

首先一個問題是IP如何使用,假設我有一個IP

myip='111.222.333.444:5555'
proxy = {'http': myip}
start_html = requests.post(all_url,headers=headers,data=Para,proxies=proxy)

使用起來很簡單,在requests裏多加個參數proxies就行了,那我們的思路就清晰了,跟上面User-Agent一樣,我們弄一個list,每次隨機就OK了。

驗證ip

首先是iP收集,同樣通過搜索關鍵字「ip list」我找到了這個網站http://www.xicidaili.com/nt/, 先複製幾個來用,結果發現,不能用,原來這些ip有很多是不能用的,我們需要把ip測試一下,選擇其中能用的才行。

import requests 
ip_list=['119.28.182.147:3128', '183.30.197.243:9797', '119.122.31.117:9000', '119.29.6.127:3128', '14.153.55.64:3128',
     '119.123.240.35:9797', '59.47.215.153:8080', '119.28.177.238:3128', '27.46.20.176:8888', '171.217.59.2:8888',
     '117.65.32.96:41496', '175.171.179.84:53281', '139.129.166.68:3128', '112.67.172.123:9797', '27.44.164.201:9999',
     '27.46.32.227:9797', '120.84.137.97:9000', '113.79.75.32:9797', '183.33.192.16:9797', '123.56.245.192:3128',
     '113.73.17.110:808', '183.30.197.31:9797', '115.194.164.83:8118', '183.30.197.31:9797', '112.67.162.231:9797',
     '116.226.222.125:9797', '111.230.32.95:3128', '218.93.174.188:6666', '27.46.23.89:8888', '121.231.150.201:6666']
ip_list_good=[]
for i in ip_list:
    proxy = {'http': i}
    print(proxy)
    try: 
        requests.get('http://www.baidu.com/', proxies=proxy)
    except: 
        print ('connect failed')    
    else: 
        print ('success')
        ip_list_good.append(i)
print(ip_list_good)

思路是,使用ip去訪問百度,或者你需要爬取的頁面的網址,返回正確則ip用。(當時不知道如何爬取ip,我用的是截圖然後用OneNote的識別功能把ip從圖片提取出來,再用word替換掉一些不對的符號,得到的ip_list)
通過這個測試程序可以打印出有效的ip。

爬取ip

OK經過測試我們的思路完全沒有問題,那麼我們反爬蟲的終極問題來了,怎麼讓程序自動獲取ip?
我們首先想到的是把ip網址裏的ip爬出來,然後驗證,說幹就幹。
打開ip網址http://www.xicidaili.com/nt/,按下f12,選擇你想要的ip。


我們可以得到ip地址是在這個標籤裏的,所有接下來要做的就是獲取網站所有的內容,然後提取標籤裏的IP
headers = {'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}
all_url = 'http://www.xicidaili.com/nt/  ##開始的URL地址
start_html = requests.get(all_url,headers=headers)
print(start_html.text)

start_html.text就是這個頁面所有的內容,類型是字符串,我們需要在這個字符串裏找到我們想要的ip,發現沒基礎重要不,摸們現在面臨的問題本質上是字符串的操作呀

如何從網頁中的標籤提取內容,就要用到beautifulsoup這個庫

import requests
from bs4 import BeautifulSoup
#https://www.cnblogs.com/hearzeus/p/5157016.html
headers = {'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}
all_url = 'http://www.xicidaili.com/nt/'  ##開始的URL地址
start_html = requests.get(all_url,headers=headers)
Soup = BeautifulSoup(start_html.text, 'lxml')
ip = Soup.find_all('td',class_=False)
print(ip)

我們分析頁面可以發現,ip所在的地方有標籤沒有class參數.

但是滿足條件的還有很多,需要進一步篩選。我能想到的方法都是不停循環,反覆篩選,有沒有跟好的方法呢?

於是我又去搜索,發現大佬的爬蟲用的是正則表達式,好像很牛,看看有沒有現成可以用的。
https://blog.csdn.net/xysoul/article/details/79215650
http://www.cnblogs.com/zxin/archive/2013/01/26/2877765.html

import requests
import  re
headers = {'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}
all_url = 'http://www.xicidaili.com/nt/'  ##開始的URL地址
start_html = requests.get(all_url,headers=headers)
print(re.findall(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b",start_html.text)) 

我去太牛了,ip全出來了,而且還是列表形式,但是沒有辦法提取端口呀,看看大神有沒有寫端口提取,好吧大神沒寫,沒關係我們模仿一下。
re.findall('(.*?)',start_html.text)
這一句是找到標籤裏的所有內容,我們需要的是找到連續2-5個數這樣形式的就是端口號。
模仿一下得到
re.findall(r"([0-9]{2,5})",start_html.text)
看看行不行。

import requests
import  re
headers = {'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}
all_url = 'http://www.xicidaili.com/nt/'  ##開始的URL地址
start_html = requests.get(all_url,headers=headers)
print(re.findall(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b",start_html.text)) 
#找到td標籤中連續的數字
print(re.findall(r"<td>([0-9]{2,5})</td>",start_html.text))

我去真牛!正則表達式處理字符串的能力真是無敵呀,拿個小本本給正則表達式畫上重點。

OK我們現在有了ip的列表,和端口的列表,需要要把它們合併起來,知道這題考什麼嗎?列表的操作。

IP_ip=re.findall(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b",start_html.text)
IP_port=re.findall(r"<td>([0-9]{2,5})</td>",start_html.text)
IP_all = list(map(lambda x: str(x[0])+':'+str(x[1]), zip(IP_ip, IP_port)))

OK現在我們就完成了最重要的獲取一頁ip地址了,我們只需要不斷循環,獲取所有頁面的ip地址即可,最後一個知識點,構造所有的頁面,
我們來分析一下
第一頁的網址是http://www.xicidaili.com/nt/
第二頁的網址是http://www.xicidaili.com/nt/2
我已經找到規律了,就是在基礎網址上添加數字就行了。

import requests ##導入requests
import os
from bs4 import BeautifulSoup ##導入bs4中的BeautifulSoup
import  re
IP_all_old=[]
headers = {'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}
for i in range(2,30) :
    all_url = 'http://www.xicidaili.com/wt/'+str(i)  ##開始的URL地址
    start_html = requests.get(all_url,headers=headers)
    IP_ip=re.findall(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b",start_html.text)
    IP_port=re.findall(r"<td>([0-9]{2,5})</td>",start_html.text)
    IP_all = list(map(lambda x: str(x[0])+':'+str(x[1]), zip(IP_ip, IP_port)))
    IP_all=IP_all+IP_all_old
    IP_all_old =IP_all
    print(i)
print(IP_all)

通過這個程序可以提取2到29頁的ip地址,把打印出來的ip複製到檢測ip的程序裏,然後把可以用ip複製到下載圖片程序裏的ip_list裏,我們的公式轉換圖片就可以無憂無慮的工作了。

改進後的公式轉圖片程序

import requests ##導入requests
import random
import time
import re
Gs=[
'$$Out_1+=(\frac{1}{1+(\frac{1}{2\pi*T})})*(In_0-Out_0)$$',#0
'$$Out_1=Out_0+(\frac{1}{1+(\frac{1}{2\pi*T})})*(In_0-Out_0)$$',#1
'$$A=(\frac{1}{1+(\frac{1}{2\pi*T})})$$',
'$$Out_1=(1-A)Out_0+A*In_0$$',
'$$I_c=\frac{d_q}{d_t}=(\frac{d_{(C*U_o)}}{d_t})=C*\frac{d_{U_o}}{d_t}$$',
'$$U_i=R*C(\frac{d_{U_o}}{d_t})+U_o$$',
'$$U_o(t)=U_i(1-e^{-\frac{t}{RC}})$$',
'$$\tau=RC$$',
'$$H(jw)=(\frac{U_o}{U_i})=(\frac{\frac{1}{jwc}}{R+\frac{1}{jwc}})=\frac{1}{1+jwRC}$$',
'$$\frac{U_o}{U_i}=\frac{1}{RCs+1},(s=jw,w=2\pi*f)$$',
'$$A(f)=\frac{U_o}{U_i}=\frac{1}{2\pi*fRCj+1}$$',
'$$w_c=\frac{1}{RC}$$',#0
'$$f_c=\frac{1}{2\pi*RC}$$',#1
'$$s=\frac{1-z^{-1}}{T}$$',#2
'$$H(z)=\frac{Y(z)}{X(z)}=\frac{1}{RC{\frac{1-z^{-1}}{T}+1}}=\frac{T}{RC(1-Z^{-1})+T}$$',#3
'$$X(z)=Y(z)+\frac{RC(1-Z^{-1})+T}{T}$$',#4
'$$X(z)=\frac{RC}{T}Y(z)-\frac{RC}{T}Y(z)(Z^{-1})+Y(z)$$',#5
'$$X(n)=(1+\frac{RC}{T})Y(n)-\frac{RC}{T}Y(n-1)$$',#6
'$$Y(n)=(\frac{1}{1+\frac{RC}{T}})X(n)+(\frac{\frac{RC}{T}}{1+\frac{RC}{T}})X(n-1)$$',#7
'$$Y(n)=\frac{T}{RC+T}X(n)+\frac{RC}{RC+T}Y(n-1)$$',#8
'$$A=\frac{T}{RC+T}$$',#9
'$$Y(n)=A*X(n)+(1-A)Y(n-1)$$',#10
'$$A=(\frac{1}{1+(\frac{1}{2\pi*T})})$$',#11
'$$f_c=\frac{1}{2\pi*RC}$$',#12
'$$RC=\frac{1}{2\pi*f_c}$$',#13
'$$A=\frac{T}{RC+T}$$',#14
'$$A=\frac{T}{\frac{1}{2\pi*f_c}+T}=\frac{1}{1+(\frac{1}{2\pi*Tf_c})}$$'#15
]
for i in range(len(Gs)):
    Gs[i]=Gs[i].replace("\frac","\\frac")#添加轉義字符 #m每個\frac要變成\\frac
    Gs[i]=Gs[i].replace("\t", "\\t")#'$$\tau=RC$$'要變成\\tau
ip_list=[
    '60.176.232.13:6666',
    '60.191.134.165:9999', 
    '123.57.217.208:3128', 
    '125.46.0.62:53281', 
    '60.176.232.13:6666',
    '118.187.58.34:53281',
    '101.132.122.230:3128',
    '101.251.232.221:3128', 
    '119.28.152.208:80', 
    '123.57.217.208:3128', 
    '114.215.95.188:3128', 
    '139.224.80.139:3128', 
    '202.38.92.100:3128', 
    '120.26.110.59:8080', 
    '112.74.207.50:3128', 
    '113.79.75.104:9797', 
    '101.37.79.125:3128', 
    '218.241.234.48:8080'
]
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"
    ]
img_url_all=[]
i=0
while 1:
    UA = random.choice(user_agent_list)#隨機一個瀏覽器User-Agent
    headers = {'User-Agent': UA}
    random_ip = random.choice(ip_list)#隨機一個ip
    proxy = {'http': random_ip}#構造一個代理 格式爲#{'http': '119.28.152.208:80'} 類型爲字典
    all_url = 'http://quicklatex.com/latex3.f'  ##開始的URL地址
    Para = {'formula':Gs[i],'fsize':"20px",'remhost':'quicklatex.com','mode':'0','out':'1'}
    print('success', i)
    try:
        start_html = requests.post(all_url,headers=headers,data=Para,proxies=proxy)  ##使用requests中的get方法來獲取all_url(就是這個地址)的內容 headers爲上面設置的請求頭、請務必參考requests官方文檔解釋
        # print(start_html)
    except:
        print ('connect failed',random_ip)
        print('failed',i)
    else:
        print('success',random_ip)
        # print(start_html.text)
        img_url=start_html.text.replace("\r\n"," ")
        img_url=img_url.split(' ')
        img_url=img_url[1] ##取URL 倒數第四至第九位 做圖片的名字
        # print(len(img_url))
        if len(img_url)<60:
            print("無效IP",random_ip)
            pass
        else:
            print(i,"當前有效IP",random_ip)
            img_url_all.append(img_url)
            i=i+1
        time.sleep(0.5)
    if i==(len(Gs)):
        break
print(img_url_all)
print("獲取全部鏈接")
i=0
for img_url in img_url_all:
    UA = random.choice(user_agent_list)
    random_ip = random.choice(ip_list)
    proxy = {'http': random_ip}
    headers = {'User-Agent': UA}
    img = requests.get(img_url, headers=headers)
    f = open('g'+str(i+1)+'.png', 'wb')##寫入多媒體文件必須要 b 這個參數!!必須要!!
    print("保存第"+str(i)+"張圖片",img, img_url)
    i+=1
    time.sleep(1)
    f.write(img.content) ##多媒體文件要是用conctent哦!
    f.close()

把之前的程序拆成了兩部分,一部分獲取圖片的下載鏈接,另一部負責下載程序,這樣調試起來方便一些。

通過不斷的改進我們把其實已經把常用的爬蟲知識點都給過了一遍,現在是不是對爬蟲有更直觀的瞭解了呢?你現在應該已經可以像我一樣模仿着大神的步伐來實現自己的功能了,所以你的爬蟲開始工作了嗎?

關注微信公衆號,回覆【公式圖片】即可獲取源碼哦。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章