Python網絡爬蟲

# !/usr/bin/env python
#  -*- coding;utf-8 -*-

網絡爬蟲類型:一、通用網絡爬蟲。二、聚焦網絡爬蟲(主題網絡爬蟲)。三、增量式網絡爬蟲。四、深層網絡爬蟲

一、通用網絡爬蟲
	通用網絡爬蟲首先咱們來看通用網絡爬蟲的實現原理。通用網絡爬蟲的實現原理及過程能夠簡要歸納以下。
	
		1)獲取初始的URL。初始的URL地址能夠由用戶人爲地指定,也能夠由用戶指定的某個或某幾個初始爬取網頁決定。
		
		2)根據初始的URL爬取頁面並得到新的URL。得到初始的URL地址以後,首先須要爬取對應URL地址中的網頁,爬取了對應的URL地址中的
		   網頁後,將網頁存儲到原始數據庫中, 而且在爬取網頁的同時,發現新的URL地址,同時將已爬取的URL地址存放到一個URL列表中,
		   用於去重及判斷爬取的進程。
		   
		3)將新的URL放到URL隊列中。在第2步中,獲取了下一個新的URL地址以後,會將新的URL地址放到URL隊列中。
		
		4)從URL隊列中讀取新的URL,並依據新的URL爬取網頁,同時重新網頁中獲取新URL,並重覆上述的爬取過程。
		
		5)知足爬蟲系統設置的中止條件時,中止爬取。在編寫爬蟲的時候,通常會設置相應的中止條件。若是沒有設置中止條件,爬蟲則會
		   一直爬取下去,一直到沒法獲取新的URL地址爲止,若設置了中止條件,爬蟲則會在中止條件知足時中止爬取。
		   
二、聚焦網絡爬蟲(主題網絡爬蟲)

	聚焦網絡爬蟲,因爲其須要有目的地進行爬取,因此對於通用網絡爬蟲來講,必需要增長目標的定義和過濾機制,具體來講,此時,其執行
	原理和過程須要比通用網絡爬蟲多出三步,即目標的定義、無關連接的過濾、下一步要爬取的URL地址的選取等。
	
		1)對爬取目標的定義和描述。首先要依據爬取需求定義好該聚焦網絡爬蟲爬取的目標,以及進行相關的描述。
		
		2)獲取初始的URL。
		
		3)根據初始的URL爬取頁面,並得到新的URL。
		
		4)重新的URL中過濾掉與爬取目標無關的連接。由於聚焦網絡爬蟲對網頁的爬取是有目的性的,因此與目標無關的網頁將會被過濾掉。
		   同時,也須要將已爬取的URL地址存放到一個URL列表中,用於去重和判斷爬取的進程。
		   
		5)將過濾後的連接放到URL隊列中。
		
		6)從URL隊列中,根據搜索算法,肯定URL的優先級,並肯定下一步要爬取的URL地址。在通用網絡爬蟲中,下一步爬取哪些URL地址,
		   是不過重要的,可是在聚焦網絡爬蟲中,因爲其具備目的性,故而下一步爬取哪些URL地址相對來講是比較重要的。對於聚焦網絡
		   爬蟲來講,不一樣的爬取順序,可能致使爬蟲的執行效率不一樣,因此,咱們須要依據搜索策略來肯定下一步須要爬取哪些URL地址。
		   
		7)從下一步要爬取的URL地址中,讀取新的URL,而後依據新的URL地址爬取網頁,並重覆上述爬取過程。
		
		8)知足系統中設置的中止條件時,或沒法獲取新的URL地址時,中止爬行。
		
三、爬行策略:深度優先爬行策略、廣度優先爬行策略、大站優先爬行策略、反鏈策略、其餘策略。

四、網頁更新策略:用戶體驗策略、歷史數據策略、聚類分析策略

五、網頁分析算法

	1)基於用戶行爲的網頁分析算法
	
	2)基於網絡拓撲的網頁分析算法
	
		(1)基於網頁粒度的分析算法,pageRank,谷歌搜索引擎的核心算法
		(2)基於網頁塊粒度的分析算法
		(3)基於網站粒度的分析算法
		
	三、基於網頁內容的網頁分析算法
	
網絡爬蟲由控制節點(中央控制器)、爬蟲節點、資源庫組成。
		
Urllib是python提供的用於操做URL的模塊:

	import urllib.request
	file  =  urllib.request.urlopen("網址")
	data  =  file.read() 讀取文件的所有內容,read會把讀取到的內容賦給一個字符串變量。
	dataline  =  file.readline()  讀取文件的一行內容
	dataline  =  file.readlines()  讀取文件的所有內容,readlines會把讀取到的內容賦給一個列表變量(推薦使用這種方式)
		
	咱們還可使用urllib.request裏面的urlretrieve()函數直接將對應信息寫入本地文件,格式爲:
		urllib.request.urlretrieve(url,filename = 本地文件地址)。
		urllib在使用中會形成必定的緩存,可用該語句清理:urllib.request.urlcleanup()
	
	url編碼:urllib.request.quote()
		urllib.request.quote("http:// www.sina.com.cn")      >>> 'http%3A// www.sina.com.cn'
		
	url解碼:
		urllib.request.unquote("http%3A// www.sina.com.cn")  >>>  'http:// www.sina.com.cn'

		
模擬瀏覽器登陸:

	一、使用build_opener()修改報頭
		import urllib.request
		url =  "http:// blog.csdn.net/weiwei_pig/article/details/51178226"
		headers = ("User-Agent",
			"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)
			Chrome/38.0.2125.122 Safari/537.36 SE 2.X MetaSr 1.0")
		opener  =  urllib.request.build_opener()
		opener.addheaders  =  [headers]
		data  =  opener.open(url).read()
		fhandle  =  open("D:/Python35/myweb/part4/3.html","wb")
		fhandle.write(data)
		fhandle.close()
		
		1中使用的是addheaders()方法。
		2中使用的是add_header()方法,注意末尾有無s以及有無下劃線的區別。
		
	2:使用add_header()添加報頭
		import urllib.request
		url =  "http:// blog.csdn.net/weiwei_pig/article/details/51178226"
		req = urllib.request.Request(url)
		req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/ 537.36 (KHTML, like Gecko)
		               Chrome/38.0.2125.122 Safari/537.36 SE 2.X MetaSr 1.0')
		data = urllib.request.urlopen(req).read()
		
	超時設置:file = urllib.request.urlopen("http:// yum.iqianyue.com",timeout = 1)

Http請求協議:

	(1)GET請求:直接在URL中寫上要傳遞的信息,也能夠由表單進行傳遞。若是使用表單進行傳遞,這表單中的
		信息會自動轉爲URL地址中的數據,經過URL地址傳遞。
		
		1)構建對應的URL地址,地址包含GET請求的字段名和字段內容等信息,而且URL地址知足GET請求的格式,
				即「http://網址?字段名1 = 字段內容1&字段名2 = 字段內容2」。
				
		2)以對應的URL爲參數,構建Request對象。
		
		3)經過urlopen()打開構建的Request對象。
		
		4)按需求進行後續的處理操做,好比讀取網頁的內容、將內容寫入文件等。
			import urllib.request
			url = "http:// www.baidu.com/s?wd = " key = "百度"
			key_code = urllib.request.quote(key)   #  注意對非ascii網址內容編碼
			url_all = url+key_code
			req = urllib.request.Request(url_all)
			data = urllib.request.urlopen(req).read()
			fh = open("D:/Python35/myweb/part4/5.html","wb")
			fh.write(data)
			fh.close()
			
	(2)POST請求:能夠向服務器提交數據,是一種比較主流也比較安全的數據傳遞方式,好比在登陸時,常用POST請求發送數據。
	
		1)設置好URL網址。
		
		2)構建表單數據,並使用urllib.parse.urlencode對數據進行編碼處理。
		
		3)建立Request對象,參數包括URL地址和要傳遞的數據。
		
		4)使用add_header()添加頭信息,模擬瀏覽器進行爬取。
		
		5)使用urllib.request.urlopen()打開對應的Request對象,完成信息的傳遞。
		
		6)後續處理,好比讀取網頁內容、將內容寫入文件等。
			import urllib.request
			import urllib.parse
			url  =  "http:// www.iqianyue.com/mypost/"
			#  將表單數據進行urlencode編碼處理後,使用encode()設置爲utf-8編碼
			postdata  = urllib.parse.urlencode({ "name":"nideshengri", "pass":"783211aa" }).encode('utf-8')
			req  =  urllib.request.Request(url,postdata)
			req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/ 537.36
			(KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36 SE 2.X MetaSr 1.0')
			data = urllib.request.urlopen(req).read()
			fhandle = open("D:/Python35/myweb/part4/6.html","wb")
			fhandle.write(data) fhandle.close()
			
	(3)PUT請求:請求服務器存儲一個資源,一般要指定存儲的位置。
	
	(4)DELETE請求:請求服務器刪除一個資源。
	
	(5)HEAD請求:請求獲取對應的HTTP報頭信息。
	
	(6)OPTIONS請求:能夠得到當前URL所支持的請求類型。
	
	除此以外,還有TRACE請求與CONNECT請求等,TRACE請求主要用於測試或診斷。
	
代理IP地址:
	def use_proxy(proxy_addr,url):
		import urllib.request
		proxy =  urllib.request.ProxyHandler({'http':proxy_addr})
		opener  =  urllib.request.build_opener(proxy, urllib.request.HTTPHandler)
		#  建立全局默認的opener對象,那麼,在使用urlopen()時亦會使用咱們安裝的opener對象
		urllib.request.install_opener(opener)
		data  =  urllib.request.urlopen(url).read().decode('utf-8')
		return data
		
	proxy_addr = "202.75.210.45:7777"
	data = use_proxy(proxy_addr,"http:// www.baidu.com")
	print(len(data))
		
在程序運行的過程當中,邊運行邊打印調試日誌:

	1)分別使用urllib.request.HTTPHandler()和urllib.request.HTTPSHandler()將debuglevel設置爲1。
	
	2)使用urllib.request.build_opener()建立自定義的opener對象,並使用1)中設置的值做爲參數。
	
	3)用urllib.request.install_opener()建立全局默認的opener對象,這樣,在使用urlopen()時,也會使用咱們安裝的opener對象。
	
	4)進行後續相應的操做,好比urlopen()等。
		
		import urllib.request
		httphd = urllib.request.HTTPHandler(debuglevel = 1)
		httpshd = urllib.request.HTTPSHandler(debuglevel = 1)
		opener = urllib.request.build_opener(httphd,httpshd)
		urllib.request.install_opener(opener)
		data = urllib.request.urlopen("http:// edu.51cto.com")
		
UrlError異常處理:
	第一個類是URLError類。
	第二個類是URLError類的一個字類 -- HTTPError類。
	
	通常來講,產生URLError的緣由有以下幾種可能:
		1)鏈接不上服務器
		2)遠程URL不存在
		3)無網絡
		4)觸發了HTTPError
	
	import urllib.request
	import urllib.error
	try:
		urllib.request.urlopen("http:// blog.csdn.net")
	except urllib.error.HTTPError as e:
		#  前三個異常沒有狀態碼
		if hasattr(e,"code"):
			print(e.code)
		if hasattr(e,"reason"):
			print(e.reason)
			
常見的狀態碼及含義:
	200 OK     一切正常
	301 Moved Permanently     重定向到新的URL,永久性
	302 Found     重定向到臨時的URL,非永久性
	304 Not Modified     請求的資源未更新
	400 Bad Request     非法請求
	401 Unauthorized     請求未經受權
	403 Forbidden     禁止訪問
	404 Not Found     沒有找到對應頁面
	500 Internal Server Error     服務器內部出現錯誤
	501 Not Implemented     服務器不支持實現請求所須要的功能
		
正則表達式基礎知識:
	1.原子,是正則表達式中最基本的組成單位,每一個正則表達式中至少要包含一個原子,常見的原子有如下幾類:
		1)普通字符做爲原子(字母、數字、下劃線)。
		
		2)非打印字符做爲原子。
			在一些字符串中用於格式控制的符號,、\n(匹配一個換行符)、\t(匹配一個製表符)
			
		3)通用字符做爲原子,一個原子能夠匹配一類字符。
			\w  匹配任意一個字母、數字或下劃線 \W 否
			\d  匹配任意一個十進制數           \D 否
			\s  匹配任意一個空白字符           \S 否
		
		4)原子表。
			定義一組地位平等的原子,而後匹配的時候會取該原子表中的任意一個原子進行匹配,在Python中,原子表由[]表示。
			[xyz]表示匹配裏面任一個字符
			[^]表明的是除了中括號裏面的原子都可以匹配,好比「[^xyz]py」能匹配「apy」,可是卻不能匹配「xpy
		
	二、元字符,就是正則表達式中具備一些特殊含義的字符,好比重複N次前面的字符等。
	
		.  匹配除換行符之外的任一字符     任意匹配元字符
		^  匹配字符串的開始位置           邊界限制元字符
		$  匹配字符串的結束位置           邊界限制元字符
		*  匹配前面的原子 > = 0 次          限定符
		?  匹配前面的原子 0或1 次         限定符
		+  匹配前面的原子 > = 1 次          限定符
		{n, m} 匹配前面的原子 n = < 匹配原子  = < m 限定符
		|  模式選擇符                     任選一個匹配
		() 模式單元符                     括號內的部分被當作總體使用
		
	三、模式修正符
	
		在不改變正則表達式的狀況下,經過模式修正符改變正則表達式的含義,從而實現一些匹配結果的調整等功能。
		re.I  匹配時忽略大小寫
		re.M  多行匹配
		re.L  本地化識別匹配
		re.U  根據Unicode字符及解析字符
		re.S  讓"."匹配任一字符,包括換行符
			import re
			pattern1 = "python"
			pattern2 = "python"
			string = "abcdfphp345Pythony_py"
			result1 = re.search(pattern1,string)
			result2 = re.search(pattern2,string,re.I)
			print(result1) None
			print(result2) python
			
	四、貪婪模式與懶惰模式
	
		貪婪模式的核心點就是儘量多地匹配,而懶惰模式的核心點就是儘量少地匹配。
			import re
			pattern1 = "p.*y"# 貪婪模式
			pattern2 = "p.*?y"# 懶惰模式
			string = "abcdfphp345pythony_py"
			result1 = re.search(pattern1,string)
			result2 = re.search(pattern2,string)
			print(result1)  php345pythony_py
			print(result2)  php345py
			
			默認貪婪模式轉化爲懶惰模式方法:p.*y >>> p.*?y  加一個問號
			
	五、正則表達式函數
	
		(1) re.match(pattern,string,flag) 從原字符串起始位置匹配,只返回一個結果
			第一個參數表明對應的正確表達式
			第二個參數表明對應的源字符
			第三個參數是可選參數,表明對應的標誌位,能夠放模式修正符
				import re
				string = "apythonhellomypythonhispythonourpythonend"
				pattern = ".python."
				result = re.match(pattern,string)
				result2 = re.match(pattern,string).span()
				print(result)   返回匹配詳細信息
				print(result2)  返回匹配字符的位置
			
		(2) re.search() 掃描整個字符串進行匹配,只返回一個結果
		
		(3) 全局匹配函數,輸出一個列表
			1)使用re.compile()對正則表達式進行預編譯。
			2)編譯後,使用findall()根據正則表達式從源字符串中將匹配的結果所有找出。
				import re
				string = "hellomypythonhispythonourpythonend"
				pattern = re.compile(".python.") #  預編譯
				result = pattern.findall(string) #  找出符合模式的全部結果
				#  result = re.compile(pattern).findall(string)
				print(result)
				
		(4) re.sub()函數
			re.sub(pattern, rep, string, max)
				第一個參數爲對應的正則表達式,
				第二個參數爲要替換成的字符串,
				第三個參數爲源字符串,
				第四個參數爲可選項,表明最多替換的次數,若是忽略不寫,則會將符合模式的結果所有替換。
					import re
					string = "hellomypythonhispythonourpythonend"
					pattern = "python."
					result1 = re.sub(pattern,"php",string)
					#  所有替換
					result2 = re.sub(pattern,"php",string,2)
					#  最多替換兩次
					print(result1)
					print(result2)
					
Coolie與Session:

	若是是經過Cookie保存會話信息,此時會將全部的會話信息保存在客戶端.
	若是是經過Session保存會話信息,會將對應的會話信息保存在服務器端.
	使用Session的方式來保存會話信息,大部分的時候,仍是會到Cookie.
	
	使用Python處理Cookie,在Python3中可使用Cookiejar庫進行處理,而在Python2則可使用Cookielib庫進行處理。
	進行Cookie處理的一種經常使用思路以下:
	
		1)導入Cookie處理模塊http.cookiejar。
		
		2)使用http.cookiejar.CookieJar()建立CookieJar對象。
		
		3)使用HTTPCookieProcessor建立cookie處理器,並以其爲參數構建opener對象。
		
		4)建立全局默認的opener對象。
			import urllib.request
			import urllib.parse
			import http.cookiejar
			url = "http:// bbs.chinaunix.net/member.php?mod=logging&action=login&loginsubmit=yes&loginhash = L768q"
			postdata = urllib.parse.urlencode({ "username":"weisuen", "password":"aA123456" }).encode('utf-8')
			req  =  urllib.request.Request(url,postdata)
			req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/ 537.36
				(KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36 SE 2.X MetaSr 1.0')
			#  使用http.cookiejar.CookieJar()建立CookieJar對象
			cjar = http.cookiejar.CookieJar()
			#  使用HTTPCookieProcessor建立cookie處理器,並以其爲參數構建opener對象
			opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cjar))
			#  將opener安裝爲全局
			urllib.request.install_opener(opener)
			file = opener.open(req)
			data = file.read()
			file = open("D:/Python35/myweb/part5/3.html","wb")
			file.write(data) file.close()
			url2 = "http:// bbs.chinaunix.net/"
			data2 = urllib.request.urlopen(url2).read()
			fhandle = open("D:/Python35/myweb/part5/4.html","wb")
			fhandle.write(data2)
			fhandle.close()
			
	連接爬蟲實例:
		import re
		import urllib.request
		def getlink(url):
			# 模擬成瀏覽器
			headers = ("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/ 537.36 (KHTML, like Gecko)
				Chrome/38.0.2125.122 Safari/537.36 SE 2.X MetaSr 1.0")
			opener = urllib.request.build_opener()
			opener.addheaders  =  [headers]
			# 將opener安裝爲全局
			urllib.request.install_opener(opener)
			file = urllib.request.urlopen(url)
			data = str(file.read())
			# 根據需求構建好連接表達式
			pat = '(https?:// [^\s)";]+\.(\w|/)*)'
			link = re.compile(pat).findall(data)
			# 去除重複元素
			link = list(set(link))
			return link
			
		# 要爬取的網頁連接
		url = "http:// blog.csdn.net/"
		# 獲取對應網頁中包含的連接地址
		linklist = getlink(url)
		# 經過for循環分別遍歷輸出獲取到的連接地址到屏幕上
		for link in linklist:
			print(link[0])
	
隊列:
	import queue
	a = queue.Queue()
	a.put('python')
	a.task_done()
	a.get()
	
多線程加隊列微信網絡爬蟲:

	1)整體規劃好程序執行的流程,並規劃好各線程的關係與做用。本項目中將劃分爲3個線程。
	
	2)線程1專門獲取對應網址並處理爲真實網址,而後將網址寫入隊列urlqueue中,該隊列專門用來存放具體文章的網址。
	
	3)線程2與線程1並行執行,從線程1提供的文章網址中依次爬取對應文章信息並處理,處理後將咱們須要的結果寫入對應的本地文件中。
	
	4)線程3主要用於判斷程序是否完成。由於在此若沒有一個整體控制的線程,即便線程一、2執行完,也不會退出程序,這不是咱們想要的結果,
	   因此咱們能夠創建一個新的線程,專門用來實現整體控制,每次延時60秒,延時後且存放網址的隊列urlqueue中沒有了網址數據,說明
	   線程2已經GET徹底部的網址了(不考慮線程1首次沒法將網址寫入隊列的特殊狀況,若是爬取沒問題,60秒的時間徹底足夠執行完第一次
	   爬取與寫入的操做。也不考慮線程2爬取完網址但線程1還沒有執行完下一次寫入網址的操做的狀況,由於線程1會比線程2快不少,即便線程1
	   延時較長時間等待線程2的執行,正常狀況下,線程1速度仍會比線程2快。),即此時已經爬取完全部的文章信息,因此此時能夠由線程3
	   控制退出程序。
	   
	5)在正規的項目設計的時候,咱們會但願並行執行的線程執行的時間相近,由於這樣整個程序才能達到更好的平衡,若是並行執行的線程
	   執行時間相差較大,會發生某一個線程早早執行完成,而另外一些線程遲遲未完成的狀況,這樣顯然程序不夠平衡,天然效率以及線程設
	   計有待改進。從這一點來講,本項目仍然有完善的空間。
	   
	6)創建合理的延時機制,好比在發生異常以後,進行相應的延時處理。再好比也能夠經過延時機制讓執行較快的線程進行延時,等待一下
	   執行較慢的線程。
	   
	7)創建合理的異常處理機制。
	
瀏覽器假裝技術:

	常見的反爬機制:
	   1)經過分析用戶請求的Headers信息進行反爬蟲。
	   2)經過檢測用戶行爲進行反爬蟲,好比經過判斷同一個IP在短期內是否頻繁訪問對應網站等進行分析。
	   3)經過動態頁面增長爬蟲爬取的難度,達到反爬蟲的目的。
	
	針對的破解方法:
		1)構造請求頭,模擬瀏覽器登陸
		2)使用代理服務器並常常借還代理服務器。
		3)利用工具:selenium + plantomJS 。
		
	常見頭信息中的字段:
		常見字段1
			Accept:·Accept字段主要用來表示瀏覽器可以支持的內容類型有哪些。
				text/html,·text/html表示HTML文檔。
				application/xhtml+xml,·application/xhtml+xml表示XHTML文檔。
				application/xml;·application/xml表示XML文檔。
				q=0.9,*/*;q=0.8·q表明權重係數,值介於0和1之間。
			因此這一行字段信息表示瀏覽器能夠支持text/html、application/xhtml+xml、application/xml、*/*等內容類型,
			支持的優先順序從左到右依次排列。
			
		常見字段2
			Accept-Encoding:·Accept-Encoding字段主要用來表示瀏覽器支持的壓縮編碼有哪些。
			gzip,·gzip是壓縮編碼的一種。
			deflate·deflate是一種無損數據壓縮算法。
			這一行字段信息表示瀏覽器能夠支持gzip、deflate等壓縮編碼。
			
		常見字段3
			Accept-Language:·Accept-Language主要用來表示瀏覽器所支持的語言類型。
			zh-CN,zh;·zh-CN表示簡體中文語言,zh表示中文,CN表示簡體。
			q=0.8,en-US;·en-US表示英語(美國)語言。
			q=0.5,en;·en表示英語語言。
			q=0.3
			因此之一行字段表示瀏覽器能夠支持zh-CN、zh、en-US、en等語言。
			
		常見字段4
			User-Agent:Mozilla/5.0(Windows NT 6.1;WOW64;rv:47.0)Gecko/20100101 Firefox/47.0
			User-Agent字段主要表示用戶代理,服務器能夠經過該字段識別出客戶端的瀏覽器類型、瀏覽器版本號、客戶端的
			操做系統及版本號,網頁排版引擎等客戶端信息。因此咱們以前要模擬瀏覽器登陸,主要以僞造該字段進行。
			·Mozilla/5.0表示瀏覽器名及版本信息。
			·Windows NT 6.1;WOW64;rv:47.0表示客戶端操做系統對應信息。
			·Gecko表示網頁排版引擎對應信息。
			·firefox天然表示火狐瀏覽器。
			因此這一行字段表示的信息爲對應的用戶代理信息是Mozilla/5.0(Windows NT 6.1;WOW64;rv:47.0)Gecko/
			20100101 Firefox/47.0。
			
		常見字段5
			Connection:keep-alive·Connection表示客戶端與服務器的鏈接類型,對應的字段值主要有兩種:
				·keep-alive表示持久性鏈接。
				·close表示單方面關閉鏈接,讓鏈接斷開。
			因此此時,這一行字段表示客戶端與服務器的鏈接是持久性鏈接。
			
		常見字段6
			Host:www.youku.com·Host字段表示請求的服務器網址是什麼,此時這一行字段表示請求的服務器網址是www.youku.com。
			
		常見字段7
			Referer:網址·Referer字段主要表示來源網址地址,好比咱們從http://www.youku.com網址中訪問了該網址下的子
				頁面http://tv.youku.com/?spm=0.0.topNav.5~1~3!2~A.QnQOEf,那麼此時來源網址爲http://www.youku.com,
				即此時Referer字段的值爲http://www.youku.com。
		
		import urllib.request
		import http.cookiejar
		#注意,若是要經過fiddler調試,則下方網址要設置爲"http:// www.baidu.com/"
		url= "http:// www.baidu.com"
		headers={ "Accept":" text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
					"Accept-Encoding":" gb2312,utf-8",
					"Accept-Language":" zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
					User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36
							(KHTML, like Gecko) Chrome/38.0.2125.122 Safari/ 537.36 SE 2.X MetaSr 1.0",
					"Connection": "keep-alive",
					"referer":"baidu.com"}
		cjar=http.cookiejar.CookieJar()
		opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cjar))
		headall=[]
		for key,value in headers.items():
			item=(key,value)
			headall.append(item)
		opener.addheaders = headall
		urllib.request.install_opener(opener)
		data=urllib.request.urlopen(url).read()
		fhandle=open("D:/Python35/myweb/part8/3.html","wb")
		fhandle.write(data)
		fhandle.close()
			
定向爬蟲步驟與策略

	爬取步驟:
		(1)理清爬取目標
		(2)設置網址過濾規則
		(3)設置內容採集規則
		(4)規劃採集任務
		(5)將採集結果進行相應的修正
		(6)對結果進行進一步處理

	信息篩選策略:
		(1)經過正則表達式篩選
		(2)經過Xpath表達式篩選
		(3)通篩選過xslt

經常使用python爬蟲框架:

	(1)scrapy框架
	
	(2)crawley框架
		crawlspider連接提取器:
			rules= (Rule(Linktractor(allow=r'Items/', deny='', restrice_xpaths='', allow_domains=('...')...), 
						callback='prse_item), follow=True),)
		連接提取器主要負責將response響應中符合條件的連接提取出來LinkEtractor:
			allow: 提取符合對應正則表達式的連接
			deny : 不提取符合對應正則表達式的連接
			restrict_xpaths: 使用Xpath表達式與allow共同做用提取出同時符合對應Xpath表達式和正則表達式的連接
			allow_domains: 應許提取的域名,從某個域名下提取連接
			deny_domains: 禁止提取的域名,從某個域名下提取連接
			
	(3)portia框架(可視化)
	
	(4)newspaper框架
	
	(5)python-goose框架
			
scrapy架構:
	1)Scrapy引擎
		Scrapy引擎是整個Scrapy架構的核心,負責控制整個數據處理流程,以及觸發一些事務處理。Scrapy引擎與調度器、實體管道、中間件、
		下載器、蜘蛛等組件都有關係,Scrapy引擎處於整個Scrapy框架的中心的位置,對各項組件進行控制及協調。
		
	2)調度器
		調度器主要實現存儲待爬取的網址,並肯定這些網址的優先級,決定下一次爬取哪一個網址等。咱們能夠把調度器的存儲結構當作一個
		優先隊列,調度器會從引擎中接收request請求並存入優先隊列中,在隊列中可能會有多個待爬取的網址,可是這些網址各自具備必定
		的優先級,同時調度器也會過濾掉一些重複的網址,避免重複爬取。當引擎發出請求以後,調度器將優先隊列中的下一次要爬取的網址
		返回給引擎,以供引擎進行進一步處理。
		
	3)下載器
		下載器主要實現對網絡上要爬取的網頁資源進行高速下載,因爲該組件須要經過網絡進行大量數據的傳輸,因此該組件的壓力負擔通常
		會比其餘的組件重。下載器下載了對應的網頁資源後,會將這些數據傳遞給Scrapy引擎,再由Scrapy引擎傳遞給對應的爬蟲進行處理。
		
	4)下載中間件
		下載中間件是處於下載器和Scrapy引擎之間的一個特定的組件,主要用於對下載器和Scrapy引擎之間的通訊進行處理,在下載中間件中,
		能夠加入自定義代碼,輕鬆地實現Scrapy功能的擴展,咱們在下載中間件中加入的自定義代碼,會在Scrapy引擎與下載器通訊的時候調用。
		上一章中咱們已經具體的使用過下載中間件來實現IP池和用戶代理池的相關功能。

	5)蜘蛛(也叫做爬蟲,一個Scrapy項目下可能會有多個Spiders爬蟲文件)
		蜘蛛(Spider)組件,也叫做爬蟲組件,該組件是Scrapy框架中爬蟲實現的核心。在一個Scrapy項目中,能夠有多個蜘蛛,每一個蜘蛛能夠
		負責一個或多個特定的網站。蜘蛛組件主要負責接收Scrapy引擎中的response響應(這些響應具體是下載器從互聯網中獲得的響應而後
		傳遞到Scrapy引擎中的),在接收了response響應以後,蜘蛛會對這些response響應進行分析處理,而後能夠提取出對應的關注的數據,
		也能夠提取出接下來須要處理的新網址等信息。

	6)爬蟲中間件
		爬蟲中間件是處於Scrapy引擎與爬蟲組件之間的一個特定的組件,主要用於對爬蟲組件和Scrapy引擎之間的通訊進行處理。一樣,在爬蟲
		中間件中能夠加入一些自定義代碼,很輕鬆地實現Scrapy功能的擴展。在爬蟲中間件中加入的自定義代碼,會在Scrapy引擎與爬蟲組件
		之間進行通訊的時候調用。

	7)實體管道
		實體管道主要用於接收從蜘蛛組件中提取出來的項目(item),接收後,會對這些item進行對應的處理,常見的處理主要有:清洗、驗證、
		存儲到數據庫中等。

scrapy工做流
	Scrapy框架中各項組件的工做流程的具體圖示,如圖13-2所示。箭頭所指的方向即爲數據流向的方向。
		首先,Scrapy引擎會將爬蟲文件中設置的要爬取的起始網址(默認在start_urls屬性中設置)傳遞到調度器中。隨後,依次進行:
		第1步:過程(1)中,主要將下一次要爬取的網址傳遞給Scrapy引擎,調度器是一個優先隊列,裏面可能存儲着多個要爬取的網,
				調度器會根據各網址的優先級分析出下一次要爬取的網址,而後再傳遞給Scrapy引擎。

		第2步:Scrapy引擎接收到(1)中傳過來的網址以後,過程(2)Scrapy引擎主要將網址傳遞給下載中間件。

		第3步:下載中間件接收到Scrapy引擎傳過來的網址以後,過程(3)中下載中間件會將對應的網址傳遞給下載器。

		第4步:而後,下載器接收到對應要下載的網址,而後過程(4)會向互聯網中對應的網址發送request請求,進行網頁的下載。

		第5步:互聯網中對應的網址接收到request請求以後,會有相應的response響應,隨後在過程(5)中將響應返回給下載器。

		第6步:下載器接收到響應以後,即完成了對應網頁的下載,隨後過程(6)會將對應的響應傳送給下載中間件。

		第7步:下載中間件接收到對應響應以後,會與Scrapy引擎進行通訊,過程(7)會將對應的response響應傳遞給Scrapy引擎。

		第8步:Scrapy引擎接收到response響應以後,過程(8)Scrapy引擎會將response響應信息傳遞給爬蟲中間件。

		第9步:爬蟲中間件接收到對應響應以後,過程(9)爬蟲中間件會將響應傳遞給對應的爬蟲進行處理。

		第10步:爬蟲進行處理以後,大體會有兩方面的信息:提取出來的數據和新的請求信息。而後,過程(10)爬蟲會將處理後的信息
			傳遞給爬蟲中間件。
		第11步:爬蟲中間件接收到對應信息後,過程(11)會將對應信息傳遞到Scrapy引擎。

		第12步:Scrapy引擎接收到爬蟲處理後的信息以後,會同時進行過程(12)和過程(13)。在過程(12)中,Scrapy引擎會將提取
			出來的項目實體(item)傳遞給實體管道(Item Pipeline),由實體管道對提取出來的信息進行進一步處理:過程(13)中,
			Scrapy引擎會將爬蟲處理後獲得的新的請求信息傳遞給調度器,由調度器進行進一步網址的調度。隨後,再重複執行第1~12步,
			即過程(1)~(13),一直到調度器中沒有網址調度或者異常退出爲止。以上咱們分析了Scrapy框架中各項組件的工做流程,
			此時,咱們對Scrapy框架中數據處理的過程就有了比較詳細的瞭解,理清了該過程以後,咱們在編寫Scrapy爬蟲項目的時候,
			思路就能更加清晰。

scrapy經常使用命令:

	一、全局命令:scrapy -h
		1) fetch :scrapy fetch http://www.baidu.com. 顯示爬蟲爬取的過程
			help : scrapy fetch -h
			scrapy fetch --headers --nolog http:?/news.sina.com.cn/
		2) runspider : scrapy runspider --loglevel=INFO first.py 在不依託scrapy的爬蟲項目,直接運行一個爬蟲文件
		3) setting :經過命令查看配置信息scrapy settings --配置名
		4)shell : 啓動scrapy交互終端,用於開發調試, scrapy shell http://www.baidu.com --nolog
		5) startproject
		6) version : 獲取scrapy版本信息
		7)view :下載某個網頁並用瀏覽器打開 scrapy view  網址
		
	二、項目命令:
		1)bench : 能夠測試本地硬件的性能
		2)gensider : scrapy genspider -l 建立爬蟲文件 可用的爬蟲模板basic、crawl、csvfeed、xmldeed
			命令格式: scrapy genspider -t 模板  爬蟲名 爬取網站域名
		3)check : 對爬蟲進行測試  進入到項目目錄 scrapy check mysite
		4)crawl : 啓動爬蟲命令 scrapy crawl 爬蟲名  (要進入到爬蟲項目)
		5)list : 列出當前項目可以使用的爬蟲文件
		6)edit : 爬蟲編輯命令
		7)parse : 使用默認爬蟲和處理函數對指定網站進行爬取 scrapy parse url
		
Xath表達式語法
	/  : 從根節點選取,絕對定位。
	// : 從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的位置。
	.  :選取當前節點
	.. : 選取當前節點的父節點
	@  : 選取屬性
	
	/bookstore/book[1]	                選取屬於 bookstore 子元素的第一個 book 元素。
	/bookstore/book[last()]	            選取屬於 bookstore 子元素的最後一個 book 元素。
	/bookstore/book[last()-1]	        選取屬於 bookstore 子元素的倒數第二個 book 元素。
	/bookstore/book[position()<3]	    選取最前面的兩個屬於 bookstore 元素的子元素的 book 元素。
	//title[@lang]	                    選取全部擁有名爲 lang 的屬性的 title 元素。
	//title[@lang='eng']	            選取全部 title 元素,且這些元素擁有值爲 eng 的 lang 屬性。
	/bookstore/book[price>35.00]	    選取bookstore下的book元素,且其中的price元素的值須大於35.00。
	/bookstore/book[price>35.00]/title	選取bookstore下的book元素的全部title元素,且其中的price元素的值須大於35.00。
	
   選取未知節點
	XPath 通配符可用來選取未知的 XML 元素。
		通配符	描述
		*	匹配任何元素節點。
		@*	匹配任何屬性節點。
		node()	匹配任何類型的節點。
		
		/bookstore/*	選取 bookstore 元素的全部子元素。
		//*	            選取文檔中的全部元素。
		//title[@*]	    選取全部帶有屬性的 title 元素。
		
		//book/title | //book/price	選取 book 元素的全部 title 和 price 元素。
		//title | //price	選取文檔中的全部 title 和 price 元素。
		/bookstore/book/title | //price	選取屬於 bookstore下book元素的全部title元素,以及文檔中全部的price元素。

scrapy爬蟲避免被禁止:
	(1)禁止Cookie;
		打開對應的Scrapy爬蟲項目中的settings.py文件,能夠發現文件中有如下兩行代碼,去掉註釋:
		# Disable cookies (enabled by default)
		COOKIES_ENABLED = False

	(2)設置下載延時;
		# Configure a delay for requests for the same website (default: 0)
		# See http://scrapy.readthedocs.org/en/latest/topics/settings.html#download-delay
		# See also autothrottle settings and docs DOWNLOAD_DELAY = 0.7
		DOWNLOAD_DELAY = 3  # 下載延遲,單位秒

	(3)使用IP池;
		具體方法:
			1)獲取代理服務器的IP信息;
			2)在setting.py文件中增長IP池
				IPPOOL = [
					{"ipaddr" : "host:port"},
				]
			3)在項目核心目錄建立middleware.py
				# middlewares下載中間件
				# 導入隨機數模塊,目的是隨機挑選一個IP池中的IP
				import random
				# 從settings文件(myfirstpjt.settings爲settings文件的地址)中導入設置好的IPPOOL
				from myfirstpjt.settings import IPPOOL
				# 導入官方文檔中HttpProxyMiddleware對應的模塊
				from scrapy.contrib.downloadermiddleware.httpproxy import HttpProxyMiddleware
				
				class IPPOOLS(HttpProxyMiddleware):
					# 初始化方法
					def __init__(self,ip=''):
						self.ip=ip
					# process_request()方法,主要進行請求處理
					def process_request(self,request,spider):
						# 先隨機選擇一個IP
						thisip=random.choice(IPPOOL)
						# 輸出當前選擇的IP,便於調試觀察
						print("當前使用的IP是:"+thisip["ipaddr"])
						# 將對應的IP實際添加爲具體的代理,用該IP進行爬取
						request.meta["proxy"]="http://"+thisip["ipaddr"]
			4)配置中間件到settings.py
				在settings.py文件中,與下載中間件相關的配置信息默認以下:
					# DOWNLOADER_MIDDLEWARES = { 'myfirstpjt.middlewares.MyCustomDownloaderMiddleware': 543, }
				因此如今須要對這一部分配置信息進行以下修改:
					DOWNLOADER_MIDDLEWARES = { 'myfirstpjt.middlewares.MyCustomDownloaderMiddleware': 543,
								'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware':123,
								'myfirstpjt.middlewares.IPPOOLS':125 }

	(4)使用用戶代理池;
		具體方法:
			1)收集多種瀏覽器的信息;
			
			2)在setting.py文件中增長用戶代理池。
				# 用戶代理(user-agent)池設置
				UAPOOL = [ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)"\
						 Chrome/49.0.2623.22 Safari/537.36 SE 2.X MetaSr 1.0", \
						"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0",\
						"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.5" ]
						
			3)在項目核心目錄建立user_agent_middleware.py
				# middlewares下載中間件
				# 導入隨機數模塊,目的是隨機挑選一個IP池中的IP
				import random
				# 從settings文件(myfirstpjt.settings爲settings文件的地址)中導入設置好的UAPOOL
				from myfirstpjt.settings import UAPOOL
				# 導入官方文檔中HttpProxyMiddleware對應的模塊
				from scrapy.contrib.downloadermiddleware.useragent import UserAgentMiddleware
				
				class UAmid(UserAgentMiddleware):
					# 初始化方法
					def __init__(self, ua=''):
						self.ua = ua
					# process_request()方法,主要進行請求處理
					def process_request(self,request,spider):
						# 先隨機選擇一個UA
						thisua = random.choice(UAPOOL)
						# 輸出當前選擇的UA,便於調試觀察
						print("當前使用的user_agent是:" + thisua)
						# 將對應的UA實際添加爲具體的代理,用該UA進行爬取
						request.headers.setdefault("User-Agent", thisua)
						
			4)配置中間件到settings.py
				在settings.py文件中,與下載中間件相關的配置信息默認以下:
					# Enable or disable downloader middlewares
					# See http://scrapy.readthedocs.org/en/latest/topics/downloader-middleware.html
					DOWNLOADER_MIDDLEWARES = {'mysite.middlewares.MyCustomDownloaderMiddleware': 543,
											 'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware':2,
											 'mysite.user_agent_middleware.UAmid':1 }

			5)其餘方法
				使用谷歌Cache,或者分佈式爬行等方式

			
相關文章
相關標籤/搜索