網絡爬蟲,又稱爲網頁蜘蛛(WebSpider),很是形象的一個名字。若是你把整個互聯網想象成相似於蜘蛛網同樣的構造,那麼咱們這隻爬蟲,就是要在上邊爬來爬去,順便得到咱們須要的資源。咱們之因此可以經過百度或谷歌這樣的搜索引擎檢索到你的網頁,靠的就是他們大量的爬蟲天天在互聯網上爬來爬去,對網頁中的每一個關鍵詞進行索引,創建索引數據庫。在通過複雜的算法進行排序後,這些結果將按照與搜索關鍵詞的相關度高低,依次 html
最近,主要的任務就是開發性感美女圖片大全,使用python進行圖片採集python
urllib模塊其實是綜合了url和lib的一個包。算法
url的通常格式爲:數據庫
protocol://hostname[:port]/path/[;parameters][?query]#fragment
URL 由三部分組成:json
第一部分是協議:http,https,ftp,file,ed2k…瀏覽器
第二部分是存放資源的服務器的域名系統或IP地址(有時候要包含端口號,各類傳輸協議都有默認的端口,如http的默認端口是80)服務器
第三部分是資源的具體地址,如目錄或者文件名等網絡
舉一個例子說明:app
import urllib.request response = urllib.request.urlopen("http://www.meimei169.com/") html = response.read() print(html) #二進制數據 html = html.decode('utf-8') #對二進制數據解碼 print(html)
當遇到不了解的模塊時,可經過IDLE中Help中打開Python的文檔進行搜索查看,也可使用print(模塊名.__doc__)或者help(模塊名)進行屬性和使用方法的查看。以下爲文檔中urlopen的用法:框架
實例1:在placekitten網站下載一隻貓的圖片
import urllib.request response = urllib.request.urlopen("http://www.meimei169.com/") #urlopen返回一個對象 cat_img = response.read() #對象都可用print()打印出來 # response.geturl() 獲得url #response.getcode() 返回值200,說明網站正常響應 response.info()獲得文件信息 with open('cat_300_300.jpg','wb') as f: f.write(cat_img)
可看到在當前運行目錄下已成功下載了圖片。
urlopen的url參數既能夠是字符串也能夠是一個request對象,則咱們還能夠將代碼寫成以下形式:
import urllib.request req = urllib.request.Request("http://www.meimei169.com/") response = urllib.request.urlopen(req) cat_img = response.read() with open('cat_500_600.jpg','wb') as f: f.write(cat_img)
實例2:利用百度翻譯進行翻譯
小甲魚的視頻中的實例是有道翻譯,運行結果以下:
看彈幕說是有道翻譯加了反爬蟲機制,因此本身用百度翻譯作了一個,研究了好一下子,新手仍是懵懵懂懂的,不過作出來了仍是很開心的。代碼以下所示:
import urllib.request import urllib.parse import json while True: content = input("請輸入須要翻譯的內容(退出q):") if content in['q','Q']: break else: url='http://www.meimei169.com/' data={} data['from'] = 'en' data['to'] = 'zh' data['query'] = content data['transtype'] = 'translang' data['simple_means_flag'] = 3 data = urllib.parse.urlencode(data).encode('utf-8') response = urllib.request.urlopen(url,data) html = response.read().decode('utf-8') target = json.loads(html) print("翻譯結果爲:%s"%(target['trans_result']['data'][0]['dst']))
打開翻譯首頁,點擊翻譯,在Network中找打方法爲post的項,各個瀏覽器可能有差別,可嘗試在Network裏的XHR中查找。
代碼中的url和data是復值表頭中的url和Form Data,在IE瀏覽器中我找了很久,下面分別爲360瀏覽器和IE瀏覽器的截圖:
360:
IE:
接着咱們解釋此行代碼:
data = urllib.parse.urlencode(data).encode('utf-8')
當data未賦值時,是以GET的方式提交,當data賦值後,POST將會取代GET將數據提交。如上圖所示,data必須基於某一模式,咱們使用urllib.parse.urlencode()便可將字符串轉換爲須要的模式。
代碼中使用了josen模塊,由於直接打印出html出來的是json格式的數據不利於直接觀看。最終運行結果以下所示:
爲何要進行隱藏操做?由於若是一個IP在必定時間訪問過於頻繁,那麼就會被被訪問網站進行反爬蟲攔截,沒法進行咱們爬蟲的後續工做了,因此要給爬蟲披上一層神祕的面紗,從而瞞天過海嘍~
兩種方法隱藏(修改)headers:
(1)經過Request的headers參數修改
(2)經過Request.add_header(key,val)方法修改
文檔中說到headers必須是字典的形式,因此方法(1)直接經過增長字典鍵和對應值的方式來進行隱藏,以下所示,找到Request Headers中的User-Agent對應的值進行添加。
import urllib.request import urllib.parse import json while True: content = input("請輸入須要翻譯的內容(退出q):") if content in['q','Q']: break else: url='http://www.meimei169.com/' head = {} head['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36' data={} data['from'] = 'en' data['to'] = 'zh' data['query'] = content data['transtype'] = 'translang' data['simple_means_flag'] = 3 data = urllib.parse.urlencode(data).encode('utf-8') req = urllib.request.Request(url,data,head) response = urllib.request.urlopen(req) html = response.read().decode('utf-8') target = json.loads(html) print("翻譯結果爲:%s"%(target['trans_result']['data'][0]['dst']))
運行結果及headers是否正確輸入的檢查:
請輸入須要翻譯的內容(退出q):love 翻譯結果爲:愛 請輸入須要翻譯的內容(退出q):q >>> req.headers #檢查 {'User-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'}
第二種方法:
import urllib.request import urllib.parse import json while True: content = input("請輸入須要翻譯的內容(退出q):") if content in['q','Q']: break else: url='http://www.meimei169.com/' ## head = {} ## head['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36' data={} data['from'] = 'en' data['to'] = 'zh' data['query'] = content data['transtype'] = 'translang' data['simple_means_flag'] = 3 data = urllib.parse.urlencode(data).encode('utf-8') ## req = urllib.request.Request(url,data,head)#替換成下一句,由於再也不引用上面的head因此去掉head req = urllib.request.Request(url,data) #使用add_header(key,value) req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36') response = urllib.request.urlopen(req) html = response.read().decode('utf-8') target = json.loads(html) print("翻譯結果爲:%s"%(target['trans_result']['data'][0]['dst']))
第三種方法是引入休息時間,調用time模塊的time.sleep來延長時間以免網站認爲是爬蟲非法訪問。
第四種方法是引入代理,代理把看到的內容返回給你,因此能夠達到一樣的效果。使用代理的步驟以下:
1. 參數是一個字典 {‘類型’:‘代理ip:端口號’}
proxy_support = urllib.request.ProxyHandler({})
2. 定製、建立一個 opener
opener = urllib.request.build_opener(proxy_support)
3a. 安裝 opener
urllib.request.install_opener(opener)
3b. 調用 opener
opener.open(url)
import urllib.request url='http://www.meimei169.com/' ##iplist=[''] proxy_support = urllib.request.ProxyHandler({'http':'115.46.123.180:8123'}) #proxy_support = urllib.request.ProxyHandler({'http':random.choice(iplist)}) opener=urllib.request.build_opener(proxy_support) opener.addheaders=[('User-Agent','Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36')] urllib.request.install_opener(opener) response=urllib.request.urlopen(url) html=response.read().decode('utf-8') print(html)
運行結果以下所示,返回的IP地址是你的代理IP地址。
跟着小甲魚的視頻去煎蛋網抓取妹子圖啦,下述內容將自動進行和諧咔咔咔...
思路:新建本地保存圖片文件夾→打開網站→記住圖片的地址→保存圖片到相應的文件夾
如圖爲煎蛋網妹子圖網頁顯示,圖片是按照頁碼來放置的。
咱們發現點擊不一樣的頁碼,url改變的只是頁碼處的數字。
http://jandan.net/ooxx/page-190#comments
首先咱們要獲取頁碼,在頁碼處右鍵點擊審查元素,以下所示:
則咱們能夠讀取到網頁的html,而後使用find函數來找到[190]中的數字190,也就是當前頁碼。
接着咱們要獲取當前頁碼下每張圖片的url,一樣在圖片點擊右鍵選擇審查元素,可看到圖片的地址以下:
嘻嘻,是gakki。以上是準備工做,接着咱們就能夠寫出大概的框架來,其他的內容由函數封裝實現
def download_mm(folder = 'ooxx',pages = 10): os.mkdir(folder) os.chdir(folder) url='http://www.meimei169.com/' page_num = int(get_page(url)) for i in range(pages): page_num -= i page_url = url + 'page-' + str(page_num) + '#comments' img_addrs = find_imgs(page_url) save_imgs(folder,img_addrs)
完整實現代碼以下所示:
import urllib.request import os def url_open(url): req = urllib.request.Request(url) req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36') response = urllib.request.urlopen(req) html = response.read() return html def get_page(url): html = url_open(url).decode('utf-8') a = html.find('current-comment-page') + 23 b = html.find(']',a) return html[a:b] def find_imgs(url): html = url_open(url).decode('utf-8') img_addrs = [] a = html.find('img src=') while a != -1: b = html.find('.jpg',a,a+255) if b != -1: img_addrs.append(html[a+9:b+4]) else: b = a + 9 a = html.find('img src=',b) return img_addrs def save_imgs(folder,img_addrs): for each in img_addrs: filename = each.split('/')[-1] with open(filename, 'wb') as f: img = url_open("http:"+each) f.write(img) def download_mm(folder = 'ooxx',pages = 10): os.mkdir(folder) os.chdir(folder) url='http://www.meimei169.com/' page_num = int(get_page(url)) for i in range(pages): page_num -= i page_url = url + 'page-' + str(page_num) + '#comments' img_addrs = find_imgs(page_url) save_imgs(folder,img_addrs) if __name__ =='__main__': download_mm()
成功在本地新建的文件夾中獲取到了jpg的圖片。
(1)URLError
當urlopen沒法處理一個響應的時候,就會引起URLError異常。 一般,沒有網絡鏈接或者對方服務器壓根兒不存在的狀況下,就會引起這個異常。同時,這個URLError會伴隨一個reason屬性,用於包含一個由錯誤編碼和錯誤信息組成的元組。
(2)HTTPError
HTTPError是URLError的子類,服務器上每個HTTP的響應都包含一個數字的「狀態碼」。有時候狀態碼會指出服務器沒法完成的請求類型,通常狀況下Python會幫你處理一部分這類響應(例如,響應的是一個「重定向」,要求客戶端從別的地址來獲取文檔,那麼urllib會自動爲你處理這個響應。);可是呢,有一些沒法處理的,就會拋出HTTPError異常。這些異常包括典型的:404(頁面沒法找到),403(請求禁止)和401(驗證請求)。
下述舉例說明Python處理異常的兩種方法:
from urllib.request import Request,urlopen from urllib.error import URLError,HTTPError req = Request(someurl) try: response = urlopen(req) except HTTPError as e: print('The server coudln\'t fulfill the request.') print('Error code:',e.code) except URLError as e: print('We failed to reach a server.') print('Reason:',e.reason) else: #do something
注意HTTPError要在URLError前面。
from urllib.request import Request,urlopen from urllib.error import URLError,HTTPError req = Request(someurl) try: response = urlopen(req) except HTTPError as e: if hasattr(e,'reason') print('We failed to reach a server.') print('Reason:',e.reason) elif hasattr(e,'code'): print('The server coudln\'t fulfill the request.') print('Error code:',e.code) else: #do something