摘要:并不是所有爬蟲都遵守,一般只有大型搜索引擎爬蟲才會遵守。的端口號為的端口號為工作原理網(wǎng)絡(luò)爬蟲抓取過程可以理解為模擬瀏覽器操作的過程。表示服務(wù)器成功接收請求并已完成整個處理過程。
爬蟲概念
數(shù)據(jù)獲取的方式:
企業(yè)生產(chǎn)的用戶數(shù)據(jù):大型互聯(lián)網(wǎng)公司有海量用戶,所以他們積累數(shù)據(jù)有天然優(yōu)勢。有數(shù)據(jù)意識的中小型企業(yè),也開始積累的數(shù)據(jù)。
數(shù)據(jù)管理咨詢公司
政府/機構(gòu)提供的公開數(shù)據(jù)
第三方數(shù)據(jù)平臺購買數(shù)據(jù)
爬蟲爬取數(shù)據(jù)
什么是爬蟲
抓去網(wǎng)頁數(shù)據(jù)的程序
網(wǎng)頁三大特征:
每個網(wǎng)頁都有自己的URL
網(wǎng)頁都使用HTML標記語言來描述頁面信息
網(wǎng)頁都使用HTTP/HTTPS協(xié)議來傳輸HTML數(shù)據(jù)
爬蟲的設(shè)計思路
確定需要爬取的網(wǎng)頁URL地址
通過HTTP/HTTPS協(xié)議來獲取對應(yīng)的HTML頁面
提取HTML頁面中的數(shù)據(jù)
如果是需要的數(shù)據(jù),就保存起來
如果頁面是其它URL,那就繼續(xù)爬取
如何抓取HTML頁面
HTTP協(xié)議請求的處理,urllib, urllib2, requests,處理后的請求可以模擬瀏覽器發(fā)送請求,獲取服務(wù)器響應(yīng)的文件
解析服務(wù)器響應(yīng)的內(nèi)容
re, xpath(常用), BeautifulSoup4(bs4), jsonpath, pyquery等使用某種描述性一樣來給需要提取的數(shù)據(jù)定義一個匹配規(guī)則,符合這個規(guī)則的數(shù)據(jù)就會被匹配。
如何采集動態(tài)HTML,驗證碼的處理
Selenium(自動化測試工具) + PhantomJS(無界面瀏覽器)
驗證碼處理通過Tesseract: 機器圖像識別系統(tǒng)(圖片中的文本識別)
Scrapy框架
(Scrapy, Pyspider)
高性能高定制型(異步網(wǎng)絡(luò)框架twisted),所以數(shù)據(jù)下載速度快
提供了數(shù)據(jù)存儲,數(shù)據(jù)下載,提取規(guī)則等組件
分布式策略
是否有那么多的機器去做分布式?
獲取的數(shù)據(jù)是否值得搭建分布式系統(tǒng)?
使用scrapy-redis來搭建,在Scrapy的基礎(chǔ)上添加了一套 Redis數(shù)據(jù)庫為核心的一套組件,讓Scrapy框架支持分布式的功能。主要在Redis中做請求指紋去重,請求分配,數(shù)據(jù)臨時存儲
爬蟲 - 反爬蟲 - 反反爬蟲
反爬蟲: User-Agent, IP, 代理, 驗證碼, 動態(tài)數(shù)據(jù)加載, 加密數(shù)據(jù)
數(shù)據(jù)的價值,是否值得去費勁去做反爬蟲,一般做到代理階段或封IP。
機器成本 + 人力成本 > 數(shù)據(jù)價值
爬蟲和反爬蟲之間的斗爭,最后一定是爬蟲獲勝。
只要是真實用戶可以瀏覽的網(wǎng)頁數(shù)據(jù),爬蟲就一定能爬下來。(爬蟲模擬瀏覽器獲取數(shù)據(jù))
爬蟲集合awesome-spider
通用爬蟲
搜索引擎使用的爬蟲系統(tǒng)
目標:盡可能把互聯(lián)網(wǎng)上所有的網(wǎng)頁下載下來,放到本地服務(wù)器里形成備份,再對這些網(wǎng)頁做相關(guān)處理(提取關(guān)鍵字,去掉廣告),最后提供一個用戶檢索接口
抓取流程:
首先選取一部分已有的URL,把這些URL放到待爬取隊列。
從隊列里去取出這些URL,然后解析DNS得到主機IP,然后去這個IP對應(yīng)的服務(wù)器下載HTML頁面,保存到搜索引擎的本地服務(wù)器里,之后把這個已經(jīng)爬過的URL放入到已經(jīng)爬取隊列中
分析網(wǎng)頁內(nèi)容,找出網(wǎng)頁中的其它URL內(nèi)容,繼續(xù)爬取。
搜索引擎如何獲取一個新網(wǎng)站的URL:
主動向搜索引擎提交網(wǎng)址: 百度搜索資源平臺
在其它網(wǎng)站設(shè)置外鏈
搜索引擎會和DNS服務(wù)商進行合作,可以快速收錄新的網(wǎng)站
通用爬蟲并不是萬物皆可爬,它也需要遵守規(guī)則:
Robots協(xié)議,協(xié)議會指明通用爬蟲可以爬取網(wǎng)頁的權(quán)限。
Robots.txt并不是所有爬蟲都遵守,一般只有大型搜索引擎爬蟲才會遵守。
通用爬蟲工作流程:
爬取網(wǎng)頁 -> 存儲數(shù)據(jù) -> 內(nèi)容處理 -> 提供檢索/排名服務(wù)
搜索引擎排名:
PageRank值:根據(jù)網(wǎng)站的流量(pv),流量越高,排名約靠前
競價排名
通用爬蟲的缺點:
只能提供和文本相關(guān)的內(nèi)容(HTML,Word,PDF)等,但是不能提供多媒體(音樂,視頻,圖片)和二進制文件。
提供的結(jié)果千篇一律,不能針對不同領(lǐng)域的人提供不同的搜索結(jié)果。
不能理解人類語義上的檢索。
DNS: 把域名解析成IP
聚焦爬蟲
爬蟲程序員寫的針對某種內(nèi)容爬蟲。(針對通用爬蟲的缺點)
面向主題爬蟲,面向需求爬蟲,會針對某種特定的內(nèi)容去爬取信息,而且會保證內(nèi)容信息和需求盡可能相關(guān)。
HTTP&HTTPSHTTP協(xié)議(HyperText Transfer Protocol,超文本傳輸協(xié)議):是一種發(fā)布和接收HTML頁面的方法。
HTTPS(Hypertext Transfer Protocol over Secure Socket Layer)簡單講是HTTP的安全版,在HTTP下加入SSL層。
SSL(Secure Sockets Layer 安全套接層)主要用于Web的安全傳輸協(xié)議,在傳輸層對網(wǎng)絡(luò)連接進行加密,保障在Internet上數(shù)據(jù)傳輸?shù)陌踩?/p>
HTTP的端口號為80
HTTPS的端口號為443
HTTP工作原理
網(wǎng)絡(luò)爬蟲抓取過程可以理解為模擬瀏覽器操作的過程。
瀏覽器的主要功能是向服務(wù)器發(fā)出請求,在瀏覽器窗口中展示您選擇的網(wǎng)絡(luò)資源,HTTP是一套計算機通過網(wǎng)絡(luò)進行通信的規(guī)則。
常用的請求報頭:
Host (主機和端口號): 對應(yīng)網(wǎng)址URL中的Web名稱和端口號,用于指定被請求資源的Internet主機和端口號,通常屬于URL的一部分。
Connection (鏈接類型): 表示客戶端與服務(wù)連接類型
Client 發(fā)起一個包含 Connection:keep-alive 的請求,HTTP/1.1使用 keep-alive 為默認值。
Server收到請求后:如果 Server 支持 keep-alive,回復(fù)一個包含 Connection:keep-alive 的響應(yīng),不關(guān)閉連接; 如果 Server 不支持keep-alive,回復(fù)一個包含 Connection:close 的響應(yīng),關(guān)閉連接。
如果client收到包含 Connection:keep-alive 的響應(yīng),向同一個連接發(fā)送下一個請求,直到一方主動關(guān)閉連接。
keep-alive在很多情況下能夠重用連接,減少資源消耗,縮短響應(yīng)時間,比如當(dāng)瀏覽器需要多個文件時(比如一個HTML文件和相關(guān)的圖形文件),不需要每次都去請求建立連接。
Upgrade-Insecure-Requests (升級為HTTPS請求): 升級不安全的請求,意思是會在加載 http 資源時自動替換成 https 請求,讓瀏覽器不再顯示https頁面中的http請求警報。(HTTPS 是以安全為目標的 HTTP 通道,所以在 HTTPS 承載的頁面上不允許出現(xiàn) HTTP 請求,一旦出現(xiàn)就是提示或報錯。)
User-Agent (瀏覽器名稱): 是客戶瀏覽器的名稱
Accept (傳輸文件類型): 指瀏覽器或其他客戶端可以接受的MIME(Multipurpose Internet Mail Extensions(多用途互聯(lián)網(wǎng)郵件擴展))文件類型,服務(wù)器可以根據(jù)它判斷并返回適當(dāng)?shù)奈募袷健?/p>
Accept: */*:表示什么都可以接收。
Accept:image/gif:表明客戶端希望接受GIF圖像格式的資源;
Accept:text/html:表明客戶端希望接受html文本。
Accept: text/html, application/xhtml+xml;q=0.9, image/*;q=0.8:表示瀏覽器支持的 MIME 類型分別是 html文本、xhtml和xml文檔、所有的圖像格式資源。html中文件類型的accept屬性有哪些
Referer (頁面跳轉(zhuǎn)處): 表明產(chǎn)生請求的網(wǎng)頁來自于哪個URL,用戶是從該 Referer頁面訪問到當(dāng)前請求的頁面。這個屬性可以用來跟蹤Web請求來自哪個頁面,是從什么網(wǎng)站來的等。有時候遇到下載某網(wǎng)站圖片,需要對應(yīng)的referer,否則無法下載圖片,那是因為人家做了防盜鏈,原理就是根據(jù)referer去判斷是否是本網(wǎng)站的地址,如果不是,則拒絕,如果是,就可以下載;
Accept-Encoding(文件編解碼格式): 指出瀏覽器可以接受的編碼方式。編碼方式不同于文件格式,它是為了壓縮文件并加速文件傳遞速度。瀏覽器在接收到Web響應(yīng)之后先解碼,然后再檢查文件格式,許多情形下這可以減少大量的下載時間。例如:Accept-Encoding:gzip;q=1.0, identity; q=0.5, *;q=0
Accept-Language(語言種類): 指出瀏覽器可以接受的語言種類,如en或en-us指英語,zh或者zh-cn指中文,當(dāng)服務(wù)器能夠提供一種以上的語言版本時要用到。
Accept-Charset(字符編碼): 指出瀏覽器可以接受的字符編碼。例如:Accept-Charset:iso-8859-1,gb2312,utf-8
Cookie (Cookie): 瀏覽器用這個屬性向服務(wù)器發(fā)送Cookie。Cookie是在瀏覽器中寄存的小型數(shù)據(jù)體,它可以記載和服務(wù)器相關(guān)的用戶信息,也可以用來實現(xiàn)會話功能
Content-Type (POST數(shù)據(jù)類型): POST請求里用來表示的內(nèi)容類型。例如:Content-Type = Text/XML; charset=gb2312:
常用的響應(yīng)報頭(了解):
Cache-Control:must-revalidate, no-cache, private: 告訴客戶端,服務(wù)端不希望客戶端緩存資源,在下次請求資源時,必須要從新請求服務(wù)器,不能從緩存副本中獲取資源。
Connection:keep-alive: 客戶端服務(wù)器的tcp連接也是一個長連接,客戶端可以繼續(xù)使用這個tcp連接發(fā)送http請求
Content-Encoding:gzip: 告訴客戶端,服務(wù)端發(fā)送的資源是采用gzip編碼的,客戶端看到這個信息后,應(yīng)該采用gzip對資源進行解碼。
Content-Type:text/html;charset=UTF-8: 告訴客戶端,資源文件的類型,還有字符編碼,客戶端通過utf-8對資源進行解碼,然后對資源進行html解析。
Date:Sun, 21 Sep 2016 06:18:21 GMT: 服務(wù)端發(fā)送資源時的服務(wù)器時間,GMT是格林尼治所在地的標準時間。http協(xié)議中發(fā)送的時間都是GMT的,這主要是解決在互聯(lián)網(wǎng)上,不同時區(qū)在相互請求資源的時候,時間混亂問題。
Expires:Sun, 1 Jan 2000 01:00:00 GMT: 這個響應(yīng)頭也是跟緩存有關(guān)的,告訴客戶端在這個時間前,可以直接訪問緩存副本,很顯然這個值會存在問題,因為客戶端和服務(wù)器的時間不一定會都是相同的,如果時間不同就會導(dǎo)致問題。所以這個響應(yīng)頭是沒有Cache-Control:max-age=*這個響應(yīng)頭準確的,因為max-age=date中的date是個相對時間.
Pragma:no-cache: 這個含義與Cache-Control等同。
Server:Tengine/1.4.6: 這個是服務(wù)器和相對應(yīng)的版本,只是告訴客戶端服務(wù)器的信息。
Transfer-Encoding:chunked: 這個響應(yīng)頭告訴客戶端,服務(wù)器發(fā)送的資源的方式是分塊發(fā)送的。
響應(yīng)狀態(tài)碼:
100~199:表示服務(wù)器成功接收部分請求,要求客戶端繼續(xù)提交其余請求才能完成整個處理過程。
200~299:表示服務(wù)器成功接收請求并已完成整個處理過程。常用200(OK 請求成功)。
300~399:為完成請求,客戶需進一步細化請求。例如:請求的資源已經(jīng)移動一個新地址、常用302(所請求的頁面已經(jīng)臨時轉(zhuǎn)移至新的url)、307和304(使用緩存資源)。
400~499:客戶端的請求有錯誤,常用404(服務(wù)器無法找到被請求的頁面)、403(服務(wù)器拒絕訪問,權(quán)限不夠)。
500~599:服務(wù)器端出現(xiàn)錯誤,常用500(請求未完成。服務(wù)器遇到不可預(yù)知的情況)。
Cookie 和 Session:
因為服務(wù)器和客戶端的交互僅限于請求/響應(yīng)過程,結(jié)束之后便斷開,在下一次請求時,服務(wù)器會認為新的客戶端。為了維護他們之間的鏈接,讓服務(wù)器知道這是前一個用戶發(fā)送的請求,必須在一個地方保存客戶端的信息
Cookie:通過在客戶端 記錄的信息確定用戶的身份。
Session:通過在服務(wù)器端 記錄的信息確定用戶的身份。
urllib.request
linux中的py源碼文件位置:
python自帶:vim /usr/lib/python2.7/urllib2.py
pip安裝:vim /usr/local/lib/python3.6/site-packages/django/http/cookie.py
urllib2.urlopen
# -*- coding:utf-8 -*- import urllib.request as urllib2 # 返回類文件對象 response = urllib2.urlopen("http://www.baidu.com/") # urlopen不支持構(gòu)造 # 服務(wù)器返回類文件對象支持python文件對象的操作方法 # read()方法就是讀取文件里面的全部內(nèi)容,返回字符串 html = response.read() print(html)
Request
# -*- coding:utf-8 -*- import urllib.request as urllib2 ua_headres = { "User_Agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Mobile Safari/537.36" } # urllib2.Request(url, data, headres) # 通過urllib2.Request()方法構(gòu)造一個請求對象 requset = urllib2.Request("http://www.baidu.com", headers=ua_headres) # 返回類文件對象, urlopen不支持構(gòu)造 response = urllib2.urlopen(requset) # 服務(wù)器返回類文件對象支持python文件對象的操作方法 # read()方法就是讀取文件里面的全部內(nèi)容,返回字符串 html = response.read() print(html)
User_Agent,是發(fā)送請求必須帶的請求頭
Response響應(yīng)
response是服務(wù)器響應(yīng)的類文件,除了支持文件操作的方法外,常用的方法也有:
respnse.getcode(), response.geturl(), response.info()
#condig=utf-8 import urllib.request as urllib2 # print(dir(urllib2)) ua_headres = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.4620.400 QQBrowser/9.7.13014.400" } request = urllib2.Request("http://www.baidu.com/", headers=ua_headres) response = urllib2.urlopen(request) html = response.read() # 返回HTTP的響應(yīng)碼,成功返回200 # 4 服務(wù)器頁面出錯, 5 服務(wù)器問題 print(response.getcode()) # 返回實際數(shù)據(jù)的url,防止重定向問題 print(response.geturl()) # 返回服務(wù)器響應(yīng)報頭信息 print(response.info()) # print(dir(response))
User-Agent歷史
如果用一個合法的身份去請求別人網(wǎng)站,就是歡迎的,所以就應(yīng)該給這個代碼加上一個身份,就是所謂的User-Agent頭。
urllib2默認的User-Agent頭為:Python-urllib/x.y(x和y是Python主版本和次版本號,例如 Python-urllib/2.7
Mosaic世界上第一個瀏覽器:美國國家計算機應(yīng)用中心
Netscape,網(wǎng)景:Netscape(支持框架)
Microsoft微軟:Internet Explorer
第一次瀏覽器大戰(zhàn):網(wǎng)景公司失敗
Mozilla 基金組織:Firefox 火狐 內(nèi)核(Gecko內(nèi)核)(瀏覽器支持內(nèi)核開始,User-Agent開始逐漸使用)
User-Agent 決定用戶的瀏覽器,為了獲取更好的HTML頁面效果
IE就給自己披著了個Mozilla的外皮
內(nèi)核:
Mozilla: Firefox (Gecko)
IE: Trident
Opera: Presto
Linux: KHTML (like Gecko)
Apple: Webkit (like KTML)
Google: Chrome (like webkit)
add_header() & get_header()
add_header(): 添加/修改 一個HTTP報頭
get_header(): 獲取一個已有的HTTP報頭值,只能第一個字母大寫,其它的必須小寫
# -*- coding:utf-8 -*- import urllib.request as urllib2 import random url = "http://www.baidu.com/" # 可以是User-Agent列表,也可以是代理列表。 作用:反反爬蟲 ua_list = [ "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50" ] # 在User-Agent列表里隨機選擇一個User-Agent user_agent = random.choice(ua_list) # 構(gòu)造一個請求 request = urllib2.Request(url) # add_header()方法,添加/修改 一個HTTP報頭 request.add_header("User-Agent", user_agent) # get_header() 獲取一個已有的HTTP報頭值,只能第一個字母大寫,其它的必須小寫 request.get_header("User-agent") response = urllib2.urlopen(request) html = response.read() print(html)
urllib.urlencode
編碼:
urlencode位置:urllib.parse.urlencode(values)。 其中values所需要編碼的數(shù)據(jù),參數(shù)只能為字典
解碼:
unquote: urllib.parse.unquote(values)
#conding=utf-8 import urllib.parse test = { "test": "我的" } # 通過urllib.urlencode()方法,將字典鍵值對按URL編碼轉(zhuǎn)換,從而能被web服務(wù)器接受。 enCodeTest = urllib.parse.urlencode(test) # 冒號解析為等號 print(enCodeTest) # test=%E6%88%91%E7%9A%84 # 通過urllib.unquote()方法,把 URL編碼字符串,轉(zhuǎn)換回原先字符串。 print(urllib.parse.unquote(enCodeTest)) # test=我的
爬取百度貼吧起始頁到結(jié)束頁的案例
#conding=utf-8 import urllib.request import urllib.parse def loadPage(url, filename): """ 作用: 根據(jù)url發(fā)送請求,獲取服務(wù)器響應(yīng)文件 url: 需要爬取的url地址 filename: 處理的文件名 """ print("正在下載" + filename) headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36" } request = urllib.request.Request(url, headers=headers) return urllib.request.urlopen(request).read() def writePage(html, filenmae): """ 作用:將html內(nèi)容寫入到本地 html: 服務(wù)器響應(yīng)文件內(nèi)容 """ print("正在保存" + filenmae) # 文件寫入 with open(filenmae, "w") as f: # with 之后,不需要做文件關(guān)閉還有其它上下文處理的操作 等同于 open(), write(), close() f.write(html.decode("utf-8")) print("-" * 30) print("thanks") def tiebaSpider(url, beginPage, endPage): """ 作用: 貼吧爬蟲調(diào)度器,負責(zé)組合處理 url: 貼吧url的前部分 beginPage: 起始頁 endPage: 結(jié)束頁 """ for page in range(beginPage, endPage+1): pn = (page - 1) * 50 filename = "第" + str(page) + "頁.html" fullurl = url + "&pn=" + str(pn) # print(fullurl) html = loadPage(fullurl, filename) writePage(html, filename) # print(html) if __name__ == "__main__": kw = input("請輸入需要爬取的貼吧名:") beginPage = int(input("請輸入起始頁:")) endPage = int(input("請輸入結(jié)束頁:")) # https://tieba.baidu.com/f?ie=utf-8&kw=javascirpt&fr=search url = "https://tieba.baidu.com/f?" key = urllib.parse.urlencode({"kw": kw}) fullurl = url + key tiebaSpider(fullurl, beginPage, endPage)
POST請求的模擬
Get和Post請求的區(qū)別:
Get請求:查詢參數(shù)在QueryString里保存
Post請求:查詢參數(shù)在FormData中保存
Post請求:
# -*- coding:utf-8 -*- import urllib.request import urllib.parse url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule" key = input("請輸入查詢翻譯的文字:") # 發(fā)送到服務(wù)器的表單數(shù)據(jù),如果是中文需要轉(zhuǎn)碼 fromdata = { "i": key, "from": "AUTO", "to": "AUTO", "smartresult": "dict", "client": "fanyideskweb", "salt": "1528127663128", "sign": "c060b56b628f82259225f751c12da59a", "doctype": "json", "version": "2.1", "keyfrom": "fanyi.web", "action": "FY_BY_REALTIME", "typoResult": "false" } data = urllib.parse.urlencode(fromdata).encode("utf-8") headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36" } request = urllib.request.Request(url, data=data, headers=headers) html = urllib.request.urlopen(request).read().decode() print(html)
獲取AJAX加載的內(nèi)容
AJAX一般返回的是JSON,直接對AJAX地址進行post或get,就返回JSON數(shù)據(jù)了。
“作為一名爬蟲工程師,最需要關(guān)注的是數(shù)據(jù)的來源”
# -*- coding:utf-8 -*- import urllib.request import urllib.parse url = "https://movie.douban.com/j/search_subjects?" headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36" } formdata = { "type": "movie", "tag": "熱門", "sort": "recommend", "page_limit": 20, "page_start": 40 } data = urllib.parse.urlencode(formdata).encode("utf-8") request = urllib.request.Request(url, data=data, headers=headers) html = urllib.request.urlopen(request).read().decode() print(html)
處理HTTPS請求 SSL證書驗證
網(wǎng)站的SSL證書是經(jīng)過CA認證的,則能夠正常訪問
多帶帶處理SSL證書,讓程序忽略SSL證書驗證錯誤
# -*- coding:utf-8 -*- import urllib.request import ssl # 表示忽略未經(jīng)核實的SSL證書認證 context = ssl._create_unverified_context() url = "https://www.12306.cn/mormhweb/" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36" } request = urllib.request.Request(url, headers = headers) # 在urlopen()方法里 指明添加 context 參數(shù) response = urllib.request.urlopen(request, context = context) print(response.read())
CA: 數(shù)字證書認證中心的簡稱,是指發(fā)放、管理、廢除數(shù)字證書的受信任的第三方機構(gòu)(類似與身份證)
CA的作用: 檢查證書持有者身份的合法性,并簽發(fā)證書,以防證書被偽造或篡改,以及對證書和密鑰進行管理
一般正常的網(wǎng)站都會主動出示自己的數(shù)字證書,來確保客戶端和網(wǎng)站服務(wù)器之間的通信數(shù)據(jù)是加密安全的.
Handler和Opener的使用
自定義Handler
# -*- coding:utf-8 -*- import urllib.request # 構(gòu)建一個HTTPHandler處理器對象,支持處理HTTP的請求 # http_hander = urllib.request.HTTPHandler() http_hander = urllib.request.HTTPHandler(debuglevel=1) # 調(diào)用build_opener()方法構(gòu)建一個自定義的opener對象,參數(shù)是構(gòu)建的處理器對象 opener = urllib.request.build_opener(http_hander) req = urllib.request.Request("http://www.baidu.com") res = opener.open(req) print(res.read().decode())
開放代理和私密代理
高匿:無法拿到真正的物理ip,只能獲取代理服務(wù)器ip
透明:能看到代理服務(wù)器ip,也可以看到物理ip地址
快代理
西刺免費代理
使用代理IP,這是爬蟲/反爬蟲的第二大招,通常也是最好用的。
很多網(wǎng)站會檢測某一段時間某個IP的訪問次數(shù)(通過流量統(tǒng)計,系統(tǒng)日志等),如果訪問次數(shù)多的不像正常人,它會禁止這個IP的訪問。
可以設(shè)置一些代理服務(wù)器,每隔一段時間換一個代理,就算IP被禁止,依然可以換個IP繼續(xù)爬取。
# -*- coding:utf-8 -*- import urllib.request # 代理開關(guān),是否啟用代理 proxyswitch = True # 公開代理 proxy_ip = { "http": "123.57.217.208:3128" } # 私密代理 授權(quán)的賬號密碼 # proxy_ip_auth = { # "http": "user:passwd@ip:prot" # } # 構(gòu)建一個handler對象,參數(shù)是一個字典類型,包括代理類型和代理服務(wù)器ip+prot http_proxy_handler = urllib.request.ProxyHandler(proxy_ip) # 構(gòu)建一個沒有代理對象的處理器對象 null_proxy_headler = urllib.request.ProxyHandler({}) if proxyswitch: opener = urllib.request.build_opener(http_proxy_handler) else: opener = urllib.request.build_opener(null_proxy_headler) # 構(gòu)建一個全局的opener,之后的所有請求都可以用urlopen()方式發(fā)送,也附帶Handler功能 urllib.request.install_opener(opener) request = urllib.request.Request("http://www.baidu.com/") response = urllib.request.urlopen(request) # response = opener.open(request) print(response.read().decode())
ProxyBasicAuthHandler(代理授權(quán)驗證):
#conding=utf-8 import urllib.request user = "" passwd = "" proxyserver = "" # 構(gòu)建一個密碼管理對象,用來保存需要處理的用戶名和密碼 passwdmgr = urllib.request.HTTPPasswordMgrWithDefaultRealm() # 添加賬戶信息,第一個參數(shù)realm是與遠程服務(wù)器相關(guān)的域信息,一般都是寫None,后面三個參數(shù)分別是 代理服務(wù)器、用戶名、密碼 passwdmgr.add_password(None, proxyserver, user, passwd) # 構(gòu)建一個代理基礎(chǔ)用戶名/密碼驗證的ProxyBasicAuthHandler處理器對象,參數(shù)是創(chuàng)建的密碼管理對象 proxy_auth_handler = urllib.request.ProxyDigestAuthHandler(passwdmgr) # 通過 build_opener()方法使用這些代理Handler對象,創(chuàng)建自定義opener對象,參數(shù)包括構(gòu)建的 proxy_handler 和 proxyauth_handler opener = urllib.request.build_opener(proxy_auth_handler) request = urllib.request.Request("http://www.baidu.com/") response = opener.open(request) print(response.read().decode())Cookie
Cookie 是指某些網(wǎng)站服務(wù)器為了辨別用戶身份和進行Session跟蹤,而儲存在用戶瀏覽器上的文本文件,Cookie可以保持登錄信息到用戶下次與服務(wù)器的會話。
HTTP是無狀態(tài)的面向連接的協(xié)議, 為了保持連接狀態(tài), 引入了Cookie機制 Cookie是http消息頭中的一種屬性
Cookie名字(Name) Cookie的值(Value) Cookie的過期時間(Expires/Max-Age) Cookie作用路徑(Path) Cookie所在域名(Domain), 使用Cookie進行安全連接(Secure)。 前兩個參數(shù)是Cookie應(yīng)用的必要條件,另外,還包括Cookie大小(Size,不同瀏覽器對Cookie個數(shù)及大小限制是有差異的)。
Cookie由變量名和值組成,根據(jù) Netscape公司的規(guī)定,Cookie格式如下:
Set-Cookie: NAME=VALUE;Expires=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE
在Python處理Cookie,一般是通過cookielib模塊和urllib2模塊的HTTPCookieProcessor處理器類一起使用。
cookielib模塊:主要作用是提供用于存儲cookie的對象
HTTPCookieProcessor處理器:主要作用是處理這些cookie對象,并構(gòu)建handler對象。
cookielib 庫
該模塊主要的對象有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar
一般情況下,只用CookieJar(),如果需要和本地文件交互,就需要使用MozillaCookjar()和LWPCookieJar()
獲取Cookie,并保存到CookieJar()對象中:
#!/usr/local/bin/python import urllib.request import http.cookiejar cookiejar = http.cookiejar.CookieJar() http_handler = urllib.request.HTTPCookieProcessor(cookiejar) opener = urllib.request.build_opener(http_handler) opener.open("http://www.baidu.com") cook_str = "" for item in cookiejar: cook_str = cook_str + item.name + "=" + item.value + ";" print(cook_str[:-1]) # BAIDUID=5DB0FC0C0DC9692BB8EE6EDC93A2EDEA:FG=1;BIDUPSID=5DB0FC0C0DC9692BB8EE6EDC93A2EDEA;H_PS_PSSID=1468_26259_21099_26350_26580;PSTM=1528615563;BDSVRTM=0;BD_HOME=0
訪問網(wǎng)站獲得cookie,并把獲得的cookie保存在cookie文件中:
#!/usr/local/bin/python import http.cookiejar import urllib.request filename = "cookie.txt" # 聲明一個MozillaCookieJar(有save實現(xiàn))對象實例來保存cookie,之后寫入文件 cookiejar = http.cookiejar.MozillaCookieJar(filename) handler = urllib.request.HTTPCookieProcessor(cookiejar) opener = urllib.request.build_opener(handler) req = opener.open("http://www.baidu.com") # 保存cookie到本地文件 cookiejar.save() print(1)非結(jié)構(gòu)化數(shù)據(jù)和結(jié)構(gòu)化數(shù)據(jù)
實際上爬蟲一共就四個主要步驟:
明確目標 (要知道準備在哪個范圍或者網(wǎng)站去搜索)
爬 (將所有的網(wǎng)站的內(nèi)容全部爬下來)
取 (去掉對沒用處的數(shù)據(jù))
處理數(shù)據(jù)(按照想要的方式存儲和使用)
re模塊
pattern = re.compile(regExp) pattern.match(): 從起始位置開始查找,返回第一個符合規(guī)則的,只匹配一次。 pattern.search(): 從任意位置開始查找,返回第一個符合規(guī)則的,只匹配一次。 pattern.findall(): 所有的全部匹配,返回列表 pattern.split(): 分割字符串,返回列表 pattern.sub(): 替換
rs.I 忽略大小寫 re.S 全文匹配
match(str, begin, end):
>>> pattern = re.compile(r"([a-z]+) ([a-z]+)", re.I) >>> m = pattern.match("hello world hello python") >>> m.group() "hello world" >>> m.group(1) "hello" >>> m.group(2) "world"
findall(str, begin, end):
>>> pattern = re.compile(r"d+") >>> pattern.findall("hello world 123 456 789") ["123", "456", "789"] >>>
split(str, count):
>>> pattern = re.compile(r"[sd;]+") >>> pattern.split("a ba;m; a ") ["a", "bx07", "m", "a", ""] >>> >>> pattern = re.compile("[sd;]+") >>> pattern.split(r"a ba;m; a ") ["a", "ba", "m", "a", ""] >>>
sub():
>>> pattern = re.compile(r"(w+)(w+)") >>> strs = "hello 123, world 456" >>> pattern.sub("hello world", strs) "hello world hello world, hello world hello world" >>>xpath
chrome插件:XPath Helper
XPath (XML Path Language) 是一門在 XML 文檔中查找信息的語言,可用來在XML文檔中對元素和屬性進行遍歷。
lxml庫:
lxml是 一個HTML/XML的解析器,主要的功能是如何解析和提取HTML/XML數(shù)據(jù)。
獲取屬性:@src, @title, @class
獲取內(nèi)容: /text()
模糊查詢: contains(@id, "模糊字符串")
xpath匹配規(guī)則:
//div[@class="pic imgcover"]/img/@src
xpath模糊匹配:
//div[contains(@id, "qiushi_tag")]
獲取某個網(wǎng)站的圖片:
#conding=utf-8 import urllib.request import urllib.parse from lxml import etree # 我乃河北,姓氏顏良 class getQdailyImg: def __init__(self, url): self.url = url def loadPage(self): print("正在下載...") headres = { "User-Agent": "ie 的user-Agent" } req = urllib.request.Request(self.url, headers=headres) html = urllib.request.urlopen(req).read().decode() xmlDom = etree.HTML(html) linkList = xmlDom.xpath("http://div[@class="pic imgcover"]/img/@src") print(linkList) self.writePage(linkList) def writePage(self, data): for item in data: with open("img.txt", "w") as f: f.write(item) if __name__ == "__main__": qdI = getQdailyImg("http://www.qdaily.com/") qdI.loadPage()
# -*- coding:utf-8 -*- import urllib.request import json from lxml import etree url = "http://www.qiushibaike.com/8hr/page/1" headers = { "user-agent": "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.0)" } req = urllib.request.Request(url, headers=headers) html = urllib.request.urlopen(req).read() text = etree.HTML(html) # 作為根目錄節(jié)點 node_list = text.xpath("http://div[contains(@id, "qiushi_tag")]") items = {} for node in node_list: username = node.xpath("./div[@class="author clearfix"]//h2/text()")[0] image = node.xpath(".//div[@class="thumb"]//@src") content = node.xpath(".//div[@class="content"]/span")[0].text zan = node.xpath(".//i")[0].text comment = node.xpath(".//i")[1].text items = { "username": username, "image": image, "content": content, "zan": zan, "comment": comment } with open("qiushi.json", "a") as f: f.write(json.dumps(items, ensure_ascii=False) + " ") print("ok")BeautifulSoup
Beautiful Soup也是一個HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML數(shù)據(jù)。
BeautifulSoup用來解析HTML比較簡單,API非常人性化,支持CSS選擇器、Python標準庫中的HTML解析器,也支持lxml的 XML解析器。
pip install bs4
beautifulsoup4文檔
tag: BeautifulSoup(html).div
attrs: BeautifulSoup(html).div.name,BeautifulSoup(html).div.attres
content: BeautifulSoup(html).span.string
#conding=utf-8 from bs4 import BeautifulSoup import requests import time def captchaMethod(captcha_data): with open("captcha.jpg", "wb") as f: f.write(captcha_data) return input("請輸入驗證碼:") def getLoginZhihu(): # 構(gòu)建Session對象,保存cookie值 sess = requests.Session() headers = { "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36 QQBrowser/4.3.4986.400" } html = sess.post("https://www.zhihu.com/#sigin", headers=headers).text bs = BeautifulSoup(html, "lxml") _xsrf = bs.find("input", attrs={"name": "_xsrf"}).get("value") captcha_url = "https://www.zhihu.com/captcha.gif?r=%d&type=login" % (time.time() * 1000) captcha = sess.get(captcha_url, headers=headers).content # 獲取驗證碼文字 text = captchaMethod(captcha) data = { "_xsrf": _xsrf, "email": "123636374@qq.com", "password": "ALARMCHIME", "captcha": text } # 登錄 獲取cookie res = sess.post("https://www.zhihu.com/login/email", data=data, headers=headers).text res = sess.get("https://www.zhihu.com/people/", headers) if __name__ == "__main__": getLoginZhihu()JSON和JSONPATH
Json和JsonPath應(yīng)用
json.loads(): 把Json格式字符串解碼轉(zhuǎn)換成Python對象
json.dumps(): 實現(xiàn)python類型轉(zhuǎn)化為json字符串,返回一個str對象 把一個Python對象編碼轉(zhuǎn)換成Json字符串
json.dump(): 將Python內(nèi)置類型序列化為json對象后寫入文件
json.load(): 讀取文件中json形式的字符串元素 轉(zhuǎn)化成python類型
dictStr = {"city": "北京", "name": "大貓"} print(json.dumps(dictStr, ensure_ascii=False)) # {"city": "北京", "name": "大劉"} listStr = [{"city": "北京"}, {"name": "大劉"}] json.dump(listStr, open("listStr.json","w"), ensure_ascii=False) strDict = json.load(open("dictStr.json")) print(strDict) # {u"city": u"u5317u4eac", u"name": u"u5927u5218"}
# -*- coding:utf-8 -*- import json import urllib.request import jsonpath headers = { "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36 QQBrowser/4.3.4986.400" } url = "https://www.lagou.com/lbs/getAllCitySearchLabels.json" request = urllib.request.Request(url, headers=headers) response = urllib.request.urlopen(request) html = response.read().decode() unicodeStr = json.loads(html) content = jsonpath.jsonpath(unicodeStr, "$..name") print(content) array = json.dumps(content, ensure_ascii=False) with open("lagoucontent.json", "w") as f: f.write(array)多線程爬蟲
一個進程可能包括多個線程,線程之間執(zhí)行任務(wù),必須通過加鎖方式控制它們(阻塞)
父線程和子線程都關(guān)系,只要父線程執(zhí)行完,不管子線程如何,都一并結(jié)束
計算機的核心是CPU,CPU承擔(dān)了所有的計算任務(wù)
一個CPU核心一次只能執(zhí)行一個任務(wù)
多個CPU核心同時可以執(zhí)行多個任務(wù)
一個CPU一次只能執(zhí)行一個進程,其它進程處于非運行
進程里包含的執(zhí)行單元叫線程
一個進程 可以包含 多個線程
一個進程的內(nèi)存空間是共享的,每個進程里的線程都可以使用這個共享空間
一個線程在使用這個共享空間的時候,其它線程必須等待它結(jié)束
通過“鎖”實現(xiàn),作用就是防止多個線程使用當(dāng)前內(nèi)存空間。
先使用的線程會加鎖,鎖上該空間,其它線程就在等待。
進程:表示程序的一次執(zhí)行
線程:CPU運算的基本調(diào)度單位
GIL: Python里的執(zhí)行通行證,而且只有唯一個。拿到通行證的線程才會執(zhí)行
Python 的多線程適用于:大量密集的I/O處理 (多帶帶都任務(wù),一個進程,只能執(zhí)行一個任務(wù))
Python 的多進程適用于:大量的密集并行計算
#conding=utf-8 import json import threading from queue import Queue import requests from lxml import etree CREAWL_EXIT = False PARSE_EXIT = False """ 采集線程 """ class ThreadCrawl(threading.Thread): def __init__(self, threadName, pageQueue, dataQueue): # threading.Thread.__init__(self) super(ThreadCrawl, self).__init__() # 多個父類,多重繼承 self.threadName = threadName self.pageQueue = pageQueue self.dataQueue = dataQueue self.headers = { "user-agent": "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.0)" } def run(self): print("start" + self.threadName) while not CREAWL_EXIT: try: page = self.pageQueue.get(False) url = "https://www.qiushibaike.com/8hr/page/" + str(page) + "/" res = requests.get(url, headers=self.headers).text self.dataQueue.put(res) except: pass print("end" + self.threadName) """ 解析線程 """ class ThreadParse(threading.Thread): def __init__(self, threadingName, dataQueue, filename): super(ThreadParse, self).__init__() self.threadingName = threadingName self.dataQueue = dataQueue self.filename = filename def run(self): print("start" + self.threadingName) while not PARSE_EXIT: try: html = self.dataQueue.get(False) self.parse(html) except: pass print("end" + self.threadingName) def parse(self, html): text = etree.HTML(html) node_list = text.xpath("http://div[contains(@id, "qiushi_tag")]") items = {} for node in node_list: username = node.xpath("./div[@class="author clearfix"]//h2/text()")[0] image = node.xpath(".//div[@class="thumb"]//@src") content = node.xpath(".//div[@class="content"]/span")[0].text zan = node.xpath(".//i")[0].text comment = node.xpath(".//i")[1].text items = { "username": username, "image": image, "content": content, "zan": zan, "comment": comment } self.filename.write(json.dumps(items, ensure_ascii=False) + " ") def main(): # 頁碼 pageQueue = Queue(10) # 放入1~10的數(shù)字 for i in range(1, 10+1): pageQueue.put(i) # 采集結(jié)果(每頁的HTML源碼) dataQueue = Queue() filename = open("duanzi.json", "a") crawlList = ["采集線程1", "采集線程2", "采集線程3"] threadcrawl = [] for threadName in crawlList: thread = ThreadCrawl(threadName, pageQueue, dataQueue) thread.start() threadcrawl.append(thread) parseList = ["解析線程1", "解析線程2", "解析線程3"] threadparse = [] for threadName in parseList: thread = ThreadParse(threadName, dataQueue, filename) thread.start() threadparse.append(thread) # 等待pageQueue隊列為空, 或者 數(shù)據(jù)隊列為空,也就是等待之前執(zhí)行的操作執(zhí)行完畢 while not pageQueue.empty() or not dataQueue.empty(): pass global CREAWL_EXIT CREAWL_EXIT = True print("queue隊列為空") global PARSE_EXIT PARSE_EXIT = True print("data隊列為空") for threadItem in crawlList: threadItem.join("") print("1") if __name__ == "__main__": main()
自動化測試unittest模塊使用和模擬用戶點擊抓取數(shù)據(jù)(拿去ajax分頁數(shù)據(jù))
# -*- coding:utf-8 -*- import unittest from selenium import webdriver from bs4 import BeautifulSoup as bs class Douyu(unittest.TestCase): def setUp(self): self.driver = webdriver.PhantomJS() # unittest測試方法必須有`test`字樣開頭 def testDouyu(self): self.driver.get("https://www.douyu.com/directory/all") while True: soup = bs(self.driver.page_source, "lxml") names = soup.find_all("h3", {"class": "ellipsis"}) viewNums = soup.find_all("span", {"class": "dy-num fr"}) for name, viewNum in zip(names, viewNums): print("房間名" + name.get_text() + "; " + "觀眾人數(shù)" + viewNum.get_text()) # 在頁面源碼中找到"下一頁"未隱藏的標簽,就退出循環(huán) if self.driver.page_source.find("shark-pager-disable-next") != -1: break # 一直點擊下一頁 self.driver.find_element_by_class_name("shark-pager-next").click() # 測試結(jié)束執(zhí)行的方法 def tearDown(self): self.driver.quit() if __name__ == "__main__": unittest.main()
執(zhí)行javascript語句:execute_script
#conding=utf-8 from selenium import webdriver import time driver = webdriver.PhantomJS("/Users/linxingzhang/Library/Python/3.6/lib/python/site-packages/selenium/webdriver/phantomjs") driver.get("https://movie.douban.com/typerank?type_name=劇情&type=11&interval_id=100:90&action=") time.sleep(3) # 向下滾動10000像素 js = "document.body.scrollTop=10000" # js="var q=document.documentElement.scrollTop=10000" # 查看頁面快照 driver.save_screenshot("douban.png") # 執(zhí)行JS語句 driver.execute_script(js) time.sleep(10) # 查看頁面快照 driver.save_screenshot("newdouban.png") driver.quit()
投票
import datetime import sys import threading import time from random import choice # choice() 方法返回一個列表,元組或字符串的隨機項 import requests from lxml import etree from fake_useragent import UserAgent # 引入隨機的UA # 設(shè)置user-agent列表,每次請求時,隨機挑選一個user-agent ua_list = UserAgent() def get_ip(): """ 獲取代理ip """ url = "http://www.xicidaili.com/nn" headers = { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", "Host": "www.xicidaili.com", "Referer": "http: // www.xicidaili.com/nn", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.6726.400 QQBrowser/10.2.2265.400" } ret = requests.get(url, headers=headers) xmlDom = etree.HTML(ret.text) data = xmlDom.xpath("http://table[@id="ip_list"]//tr") z = [] for tr in data: if tr.xpath("td"): ip = tr.xpath("td")[1].text # 獲取所有IP port = tr.xpath("td")[2].text # 獲取所有端口 z.append(ip + ":" + port) return z def get_url(url, code=0, ips=[]): """ 投票 如果因為代理IP已失效造成投票失敗,則會自動換一個代理IP后繼續(xù)投票 """ try: ip = choice(ips) print(ip, "ip" * 5) except: return False else: proxies = { "http": ip } headers = { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Host": "best.zhaopin.com", "Origin": "https: // best.zhaopin.com", "Referer": "https//best.zhaopin.com/?sid=121128100&site=sou", "User-Agent": ua_list.random } print(ua_list.random, "ua_list" * 5) try: data = {"bestid": "3713", "score": "5,5,5,5,5,5", "source": "best"} # 跳過證書的驗證 verify=False result = requests.post(url, data=data, headers=headers, proxies=proxies) print(result, "result" * 5) except requests.exceptions.ConnectionError: print("ConnectionError") if not ips: print("ip 失效") sys.exit() # 刪除不可用的代理IP if ip in ips: ips.remove(ip) # 重新請求url get_url(url, code=0, ips=[]) else: date = datetime.datetime.now().strftime("%H:%M:%S") # result.text() 投票成功顯示1 失敗顯示0 print("第%s次 [%s] [%s]:投票%s (剩余可用代理IP數(shù):%s)" % (code, date, ip, result.text, len(ips))) def main(): url = "https://best.zhaopin.com/API/ScoreCompany.ashx" # 投票的請求 ips = [] for i in range(6000): if i % 1000 == 0: ips.extend(get_ip()) # print("-" * 100) # print(ips) t = threading.Thread(target=get_url, args=(url, i, ips)) t.start() time.sleep(1) if __name__ == "__main__": main()Tesseract
機器識別中的文字識別
pip install pytesseract
識別圖片中的文字:
#conding=utf-8 import pytesseract from PIL import Image image = Image.open("./mayday.jpg") text = pytesseract.image_to_string(image) print(text)asyncio & aiohttp
通過異步庫aiohttp,asyncio爬取圖片
# -*- coding:utf-8 -*- import asyncio import os import time import aiohttp import requests class Spider(object): def __init__(self): self.num = 1 if "load-img" not in os.listdir("."): os.mkdir("load-img") self.path = os.path.join(os.path.abspath("."), "load-img") os.chdir(self.path) # 進入文件下載路徑 def run(self): start = time.time() for x in range(1, 101): # 爬取100張圖片,更改數(shù)值,爬取更多圖片 links = self.__get_img_links(x) tasks = [asyncio.ensure_future(self.__download_img( (link["id"], link["links"]["download"]) )) for link in links] loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) # if self.num >= 10: # break end = time.time() print("run %s s" % (end - start)) def __get_img_links(self, page): url = "https://unsplash.com/napi/photos" data = { "page": page, "per_page": 12, "order_by": "latest" } response = requests.get(url, params=data) if response.status_code == 200: return response.json() else: print("request %s" % response.status_code) async def __download_img(self, img): content = await self.__get_content(img[1]) with open(img[0] + ".jpg", "wb") as f: f.write(content) print("load %s page success" % self.num) self.num += 1 async def __get_content(self, link): async with aiohttp.ClientSession() as session: response = await session.get(link) content = await response.read() return content def main(): spider = Spider() spider.run() if __name__ == "__main__": main()
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/41772.html
摘要:以下這些項目,你拿來學(xué)習(xí)學(xué)習(xí)練練手。當(dāng)你每個步驟都能做到很優(yōu)秀的時候,你應(yīng)該考慮如何組合這四個步驟,使你的爬蟲達到效率最高,也就是所謂的爬蟲策略問題,爬蟲策略學(xué)習(xí)不是一朝一夕的事情,建議多看看一些比較優(yōu)秀的爬蟲的設(shè)計方案,比如說。 (一)如何學(xué)習(xí)Python 學(xué)習(xí)Python大致可以分為以下幾個階段: 1.剛上手的時候肯定是先過一遍Python最基本的知識,比如說:變量、數(shù)據(jù)結(jié)構(gòu)、語法...
摘要:且本小白也親身經(jīng)歷了整個從小白到爬蟲初入門的過程,因此就斗膽在上開一個欄目,以我的圖片爬蟲全實現(xiàn)過程為例,以期用更簡單清晰詳盡的方式來幫助更多小白應(yīng)對更大多數(shù)的爬蟲實際問題。 前言: 一個月前,博主在學(xué)過python(一年前)、會一點網(wǎng)絡(luò)(能按F12)的情況下,憑著熱血和興趣,開始了pyth...
摘要:這篇文章的題目有點大,但這并不是說我自覺對爬蟲這塊有多大見解,我只不過是想將自己的一些經(jīng)驗付諸于筆,對于如何寫一個爬蟲框架,我想一步一步地結(jié)合具體代碼來講述如何從零開始編寫一個自己的爬蟲框架年到如今,我花精力比較多的一個開源項目算是了,這是 showImg(https://segmentfault.com/img/remote/1460000018513379); 這篇文章的題目有點大...
?????? ???Hello,大家好我叫是Dream呀,一個有趣的Python博主,小白一枚,多多關(guān)照??? ???CSDN Python領(lǐng)域新星創(chuàng)作者,大二在讀,歡迎大家找我合作學(xué)習(xí) ?入門須知:這片樂園從不缺乏天才,努力才是你的最終入場券!??? ?最后,愿我們都能在看不到的地方閃閃發(fā)光,一起加油進步??? ???一萬次悲傷,依然會有Dream,我一直在最溫暖的地方等你,唱的就是我!哈哈哈~...
摘要:爬蟲架構(gòu)架構(gòu)組成管理器管理待爬取的集合和已爬取的集合,傳送待爬取的給網(wǎng)頁下載器。網(wǎng)頁下載器爬取對應(yīng)的網(wǎng)頁,存儲成字符串,傳送給網(wǎng)頁解析器。從文檔中獲取所有文字內(nèi)容正則匹配后記爬蟲基礎(chǔ)知識,至此足夠,接下來,在實戰(zhàn)中學(xué)習(xí)更高級的知識。 前言 Python非常適合用來開發(fā)網(wǎng)頁爬蟲,理由如下:1、抓取網(wǎng)頁本身的接口相比與其他靜態(tài)編程語言,如java,c#,c++,python抓取網(wǎng)頁文檔的接...
摘要:爬取幣世界標紅快訊內(nèi)容移動版引入依賴寫你自己的數(shù)據(jù)庫地址需要自己安裝客戶端數(shù)據(jù)庫表名偽造成手機寫你自己的文件地址插入了一條新數(shù)據(jù)無新數(shù)據(jù)產(chǎn)生寫你自己的文件地址時間不一致宕機使用當(dāng)前系統(tǒng)時間進行爬取時間一致正常運行主要要求掌握內(nèi)容語法 爬取幣世界標紅快訊內(nèi)容(移動版) # 引入依賴 from lxml import etree import requests import pymongo...
閱讀 1087·2021-10-08 10:04
閱讀 3525·2021-08-05 10:01
閱讀 2283·2019-08-30 11:04
閱讀 1802·2019-08-29 15:29
閱讀 848·2019-08-29 15:12
閱讀 1674·2019-08-26 12:11
閱讀 3121·2019-08-26 11:33
閱讀 1167·2019-08-26 10:23