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,或者分布式爬行等方式

			
相关文章
相关标签/搜索