1.爲何會被反爬蟲?php
對於一個常用爬蟲程序獲取網頁數據的人來講,遭遇到網站的「反爬蟲」已是司空見慣。html
爲何網站要反爬蟲?web
l 爬蟲並非一個真正用戶的流量,爬蟲會浪費網站的流量,也就是會浪費錢。ajax
l 數據對於每家公司來講都是寶貴的資源。在大數據時代,數據的價值愈來愈突出,它是不少公司的戰略資源。json
因此,一些有實力的大公司便利用反爬蟲技術來阻止別人獲取本身網站的數據。瀏覽器
2.反爬蟲的方式有哪些服務器
在實際的爬取過程當中,反爬蟲機制大概能夠分爲如下3類。cookie
l 不返回求取的網頁,例如不返回網頁或者延遲返回。網絡
l 返回非目標網頁,如返回錯誤頁、空白頁以及同一頁。app
l 增長獲取數據的難度,例如登陸的cookie驗證和驗證碼。
3.如何反反爬蟲
網站利用「反爬蟲」來阻止別人獲取本身網站的數據,但自古以來都是道高一尺、魔高一丈。寫爬蟲程序的人們又會利用各類反爬措施來獲取網站數據。
而如何讓爬蟲程序順利的運行下去,核心的思想就是讓爬蟲程序看起來像正常的用戶操做行爲。正常的用戶使用計算機訪問網站時,使用的是瀏覽器,而且速度慢,網頁切換的時間也不肯定,不會短期瀏覽不少的網頁。因此咱們能夠在這下方面想辦法。
3.1 修改請求頭
咱們可使用User-Agent的方法來修改請求頭,從而達到順利獲取網頁的目的。
from bs4 import BeautifulSoup from urllib import request,parse,error import json,re,time,random import requests # 請求頭 headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36' } url = 'https://www.baidu.com/' # 網址 # 使用requests方法 #r = requests.get(url,headers = headers) #print(r.text) # 使用urllib方法 res = request.Request(url,headers=headers) req = request.urlopen(res).read() # 獲取的的網頁是bytes格式的數據 print(req.decode('utf-8')) # 解碼成str格式的數據
除了User-Agent,咱們還須要知道其餘的http協議的字段,如Host和Referer等。
3.2 修改爬蟲的時間間隔
爬蟲若是爬取的太過頻繁,一方面是對網站的壓力大、不友好,另一方面是容易招致網站的反爬蟲措施。因此,寫爬蟲程序的時候最好在訪問的間隙設置等待時間。另外設置的時間間隔每次都同樣,也容易被看出來。咱們可使用time和random模塊來設置非固定的間隔時間。
from bs4 import BeautifulSoup from urllib import request,parse,error import json,re,time,random import requests
# 請求頭 headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36' }
url = 'https://www.baidu.com/' # 網址 # 使用requests方法 #r = requests.get(url,headers = headers) #print(r.text) # 使用urllib方法 for i in range(10): res = request.Request(url,headers=headers) req = request.urlopen(res).read() # 獲取的的網頁是bytes格式的數據 print(req.decode('utf-8')) # 解碼成str格式的數據 time.sleep(random.randint(0,3) + random.random()) # 設置0-3秒的時間間隔
3.3 使用代理
代理(Proxy)是指一種特殊的網絡服務,容許一個網絡終端(瀏覽器)經過這個服務與另一個網絡終端(服務器)進行非直接的聯繫。簡單來講就是網絡的一箇中轉之地。代理服務器像一個大的緩衝,這樣能明顯提升瀏覽的速度和效率。
並且咱們也能夠維護一個IP池。從而匿藏咱們電腦真正的IP。可是代理的IP池維護起來比較麻煩,並且不穩定。(網上有不少免費的代理IP)
3.3.1使用代理的主要思路
1.從代理ip網站爬取IP地址及端口號並儲存
2.驗證ip是否能用
3.格式化ip地址
4.在requests中或者urllib中使用代理ip爬取網站
在Requests中使用代理爬取的格式是
import requests requests.get(url, headers=headers,proxies=proxies) 其中proxies是一個字典其格式爲: 對每一個ip都有 proxies = { http: 'http://114.99.7.122:8752' https: 'https://114.99.7.122:8752' }
3.3.2.代碼
# IP地址取自國內髙匿代理IP網站:http://www.xicidaili.com/nn/ # 僅僅爬取首頁IP地址就足夠通常使用 from bs4 import BeautifulSoup import urllib import requests import random headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36' } def getHTMLText(url, proxies): r = requests.get(url, proxies=proxies) r.raise_for_status() r.encoding = r.apparent_encoding #獲取網頁正確的編碼格式 return r.text #從代理ip網站獲取代理ip列表函數,並檢測可用性,返回ip列表 def get_ip_list(url): web_data = requests.get(url, headers = headers) soup = BeautifulSoup(web_data.text, 'lxml') ips = soup.find_all('tr') ip_list = [] for i in range(1, len(ips)): ip_info = ips[i] tds = ip_info.find_all('td') ip_list.append(tds[1].text + ':' + tds[2].text) # 檢測ip可用性,移除不可用ip: for ip in ip_list: try: proxy_host = "https://" + ip proxy_temp = {"https": proxy_host} res = urllib.request.urlopen(url, proxies=proxy_temp).read() except Exception as e: ip_list.remove(ip) continue return ip_list #從ip池中隨機獲取ip列表 def get_random_ip(ip_list): proxy_list = [] for ip in ip_list: proxy_list.append('http://' + ip) print(proxy_list) proxy_ip = random.choice(proxy_list) proxies = {'http': proxy_ip} return proxies #調用代理 if __name__ == '__main__': url = 'http://www.xicidaili.com/nn/' url9 = "https://blog.csdn.net/weixin_40372371/article/details/80154707" ip_list = get_ip_list(url) proxies = get_random_ip(ip_list) test = getHTMLText(url9,proxies) print(test)
4 處理cookie,讓網頁記住登陸信息
使用cookie方法,能夠把登陸信息給記錄下來,再次運行代碼的時候能夠直接獲取以前的登錄狀態,從而不用從新登陸。
當你獲取一個URL你使用一個opener。在前面,咱們都是使用的默認的opener,也就是urlopen。它是一個特殊的opener,能夠理解成opener的一個特殊實例,傳入的參數僅僅是url,data,timeout。若是咱們須要用到Cookie,只用這個opener是不能達到目的的,因此咱們須要建立更通常的opener來實現對Cookie的設置。
from urllib import request, parse, error from http import cookiejar request_url = 'http://www.baidu.com' # 此處r是用來防止字符轉義的,若是字符串中有'\t'的話,若是不加r就會被轉義 user_agent = r'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87' # Keep-Alive功能使客戶端到服務器端的鏈接持續有效 headers = {'User-Agent': user_agent, 'Connection': 'keep-alive'} # 建立一個cookie對象,不傳遞參數說明建立了一個空的cookie對象 cookie_obj = cookiejar.CookieJar() # 建立一個cookie處理器,來管理cookie_obj handler = request.HTTPCookieProcessor(cookie_obj) # 初始化一個opener,此opener中全部通訊的cookie_obj都會在cookie對象中記錄。 # 這個cookie是沒有域限制的,也就是全局cookie opener = request.build_opener(handler) req = request.Request(request_url, headers=headers) response = opener.open(req) #print(response.read().decode('utf-8')) for obj in cookie_obj: print('Name=' + obj.name) print('Value=' + obj.value)
from urllib import request, parse, error from http import cookiejar request_url = 'http://www.baidu.com' filename = 'cookie.txt' # 此處r是用來防止字符轉義的,若是字符串中有'\t'的話,若是不加r就會被轉義 user_agent = r'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87' # Keep-Alive功能使客戶端到服務器端的鏈接持續有效 headers = {'User-Agent': user_agent, 'Connection': 'keep-alive'} # 建立一個MozillaCookie對象,用來保存COOKIE,以後寫入文件,注意這裏須要傳遞文件名稱做爲參數 cookie_obj = cookiejar.MozillaCookieJar(filename) # 建立一個cookie處理器,來管理cookie_obj handler = request.HTTPCookieProcessor(cookie_obj) # 初始化一個opener,此opener中全部通訊的cookie_obj都會在cookie對象中記錄。這個cookie是沒有域限制的,也就是全局cookie opener = request.build_opener(handler) req = request.Request(request_url, headers=headers) response = opener.open(req) # 保存到cookie文件中 # ignore_discard表示cookies將被丟棄也將它保存下來 # ignore_expires表示若是在該文件中cookies已經存在,則覆蓋原文件寫入 cookie_obj.save(ignore_discard=True, ignore_expires=True)
from urllib import request, parse, error from http import cookiejar # 此處r是用來防止字符轉義的,若是字符串中有'\t'的話,若是不加r就會被轉義 user_agent = r'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87' # Keep-Alive功能使客戶端到服務器端的鏈接持續有效 headers = {'User-Agent': user_agent, 'Connection': 'keep-alive'} # 請求URL request_url = 'http://www.baidu.com' # 記錄COOKIE的文件名稱 filename = 'cookie.txt' # 初始化一個MozillaCookie對象 cookie_obj = cookiejar.MozillaCookieJar() # 從文件中讀取cookie到對象中 cookie_obj.load(filename, ignore_discard=True, ignore_expires=True) # 初始化處理對象,此時的cookie_obj對象是帶了文件中保存的COOKIE的 handler = request.HTTPCookieProcessor(cookie_obj) opener = request.build_opener(handler) req = request.Request(request_url, headers=headers) response = opener.open(req) print(response.read().decode('utf-8'))
import urllib.request, urllib.parse, urllib.error import http.cookiejar LOGIN_URL = 'http://www.jobbole.com/wp-admin/admin-ajax.php' get_url = 'http://www.jobbole.com/' # 利用cookie請求訪問另外一個網址 values = {'action': 'user_login', 'user_login': '*****', 'user_pass': '******'} postdata = urllib.parse.urlencode(values).encode() user_agent = r'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36' headers = {'User-Agent': user_agent} cookie_filename = 'cookie_jar.txt' cookie_jar = http.cookiejar.MozillaCookieJar(cookie_filename) handler = urllib.request.HTTPCookieProcessor(cookie_jar) opener = urllib.request.build_opener(handler) request = urllib.request.Request(LOGIN_URL, postdata, headers) try: response = opener.open(request) # print(response.read().decode()) except urllib.error.URLError as e: print(e.reason) cookie_jar.save(ignore_discard=True, ignore_expires=True) # 保存cookie到cookie.txt中 for item in cookie_jar: print('Name = ' + item.name) print('Value = ' + item.value) get_request = urllib.request.Request(get_url, headers=headers) get_response = opener.open(get_request) print('我的主頁' in get_response.read().decode())
待續。。。