urllib库的使用:
urlopen()接受三个参数,urlopen(url,data=None,timeout=socket._GLOBAL_DEFAULT_TIMEOUT) ,data是访问url时要传送的数据,返回一个response对象,response对象中有一个read方法,可以返回获取到的网页内容
import urllib url = 'https://www.baidu.com/index.php?tn=monline_3_dg' print urllib.urlopen(url) print urllib.urlopen(url).read()
结果如下:
<addinfourl at 85341256L whose fp = <socket._fileobject object at 0x0000000005167A20>> <html> <head> <script> location.replace(location.href.replace("https://","http://")); </script> </head> <body> <noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript> </body> </html>
可知不加read打印出来的是该对象的描述,加了read打印出来是网页的html代码
urlretrieve () 直接将远程数据下载到本地。 urllib.urlretrieve(url[, filename[, reporthook[, data]]])
参数说明:
url:外部或者本地url
filename:指定了保存到本地的路径(如果未指定该参数,urllib会生成一个临时文件来保存数据);
reporthook:是一个回调函数,当连接上服务器、以及相应的数据块传输完毕的时候会触发该回调。我们可以利用这个回调函数来显示当前的下载进度。
data:指post到服务器的数据。该方法返回一个包含两个元素的元组(filename, headers),filename表示保存到本地的路径,header表示服务器的响应头。
一个小小的例子,还有待改进,爬取豆瓣读书的页面图片,下载并保存到本地:
# coding=utf-8
import urllib
import re import requests import sys reload(sys) sys.setdefaultencoding('utf8') url = 'https://book.douban.com/' headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/59.0"} data = requests.get(url,headers=headers).text pat = re.compile('<div class="cover">.*?<img\ssrc="(.*?)".*?alt="(.*?)".*?>',re.S) res = re.findall(pat,data) for i in res: path = 'G:\image\%s.jpg' % str(i[1]).decode('utf-8').encode('gbk', 'ignore') urllib.urlretrieve(i[0],path) print i
有些图片并不能被找到,正则表达式真难写
构造request:
import urllib2 url = 'https://www.baidu.com/index.php?tn=monline_3_dg' request = urllib2.Request(url = 'https://www.baidu.com/index.php?tn=monline_3_dg') response = urllib2.urlopen(request) print response.read()
结果同上,都是打印html代码,这样写显得逻辑清晰,可读性更好。
POST和GET数据传送:
import urllib import urllib2 values = {"username":"1016903103@qq.com","password":"XXXX"} data = urllib.urlencode(values) url = "https://passport.csdn.net/account/login?from=http://my.csdn.net/my/mycsdn" request = urllib2.Request(url,data) response = urllib2.urlopen(request) print response.read()
GET方式我们可以直接把参数写到url上
import urllib import urllib2 values={} values['username'] = "1016903103@qq.com" values['password']="XXXX" data = urllib.urlencode(values) url = "http://passport.csdn.net/account/login" geturl = url + "?"+data request = urllib2.Request(geturl) response = urllib2.urlopen(request) print response.read() print geturl
一些增强爬虫可行性的方法:
1、封装请求头Header
有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Headers 的属性
Header的一些属性:
User-Agent : 有些服务器或 Proxy 会通过该值来判断是否是浏览器发出的请求 Content-Type : 在使用 REST 接口时,服务器会检查该值,用来确定 HTTP Body 中的内容该怎样解析。 application/xml : 在 XML RPC,如 RESTful/SOAP 调用时使用 application/json : 在 JSON RPC 调用时使用 application/x-www-form-urlencoded : 浏览器提交 Web 表单时使用 在使用服务器提供的 RESTful 或 SOAP 服务时, Content-Type 设置错误会导致服务器拒绝服务
import urllib import urllib2 url = 'http://www.server.com/login' user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' values = {'username' : 'cqc', 'password' : 'XXXX' } headers = { 'User-Agent' : user_agent } data = urllib.urlencode(values) request = urllib2.Request(url, data, headers) response = urllib2.urlopen(request) page = response.read()
还可以增加一个Referer属性,服务器识别Referer是不是自己
headers = { 'User-Agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' , 'Referer':'http://www.zhihu.com/articles' }
2、Proxy代理设置
一些服务器会检测某个IP在一段时间内访问服务器的次数,次数多了可能会被封,所以你可以设置一些代理服务器来帮助你做工作,每隔一段时间换一个代理
# import urllib2 # enable_proxy = True # proxy_handler = urllib2.ProxyHandler({"http" : 'http://some-proxy.com:8080'}) # null_proxy_handler = urllib2.ProxyHandler({}) # if enable_proxy: # opener = urllib2.build_opener(proxy_handler) # else: # opener = urllib2.build_opener(null_proxy_handler) # urllib2.install_opener(opener)
URLError异常处理:
try-except语句来包围并捕获相应的异常
1、URLError异常,可能原因:没联网;连接不到特定的服务器;服务器不存在
import urllib2 requset = urllib2.Request('http://www.xxxxx.com') try: urllib2.urlopen(request) except urllib2.URLError, e: print e.reason
[Errno 11004] getaddrinfo failed
以上是预期结果,但我运行时输出的是空,debug不出来,我就留着一会儿再解决吧
2、HTTOError异常
是URLError的一个子类,利用urlopen发出请求时,会得到一个response,其中包含一个数字状态码,如下
100:继续 客户端应当继续发送请求。客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应。 101: 转换协议 在发送完这个响应最后的空行后,服务器将会切换到在Upgrade 消息头中定义的那些协议。只有在切换新的协议更有好处的时候才应该采取类似措施。 102:继续处理 由WebDAV(RFC 2518)扩展的状态码,代表处理将被继续执行。 200:请求成功 处理方式:获得响应的内容,进行处理 201:请求完成,结果是创建了新资源。新创建资源的URI可在响应的实体中得到 处理方式:爬虫中不会遇到 202:请求被接受,但处理尚未完成 处理方式:阻塞等待 204:服务器端已经实现了请求,但是没有返回新的信 息。如果客户是用户代理,则无须为此更新自身的文档视图。 处理方式:丢弃
300:该状态码不被HTTP/1.0的应用程序直接使用, 只是作为3XX类型回应的默认解释。存在多个可用的被请求资源。 处理方式:若程序中能够处理,则进行进一步处理,如果程序中不能处理,则丢弃
301:请求到的资源都会分配一个永久的URL,这样就可以在将来通过该URL来访问此资源 处理方式:重定向到分配的URL 302:请求到的资源在一个不同的URL处临时保存 处理方式:重定向到临时的URL 304:请求的资源未更新 处理方式:丢弃 400:非法请求 处理方式:丢弃 401:未授权 处理方式:丢弃 403:禁止 处理方式:丢弃 404:没有找到 处理方式:丢弃 500:服务器内部错误 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器端的源代码出现错误时出现。 501:服务器无法识别 服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法,并且无法支持其对任何资源的请求。 502:错误网关 作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。 503:服务出错 由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。
HTTPError产生后会有一个code属性,就是上面的服务器发送的错误数字状态码
import urllib2 req = urllib2.Request('http://blog.csdn.net/cqcre') try: urllib2.urlopen(req) except urllib2.HTTPError, e: print e.code print e.reason
预期结果,反正我的还是空,然后我发现了python中的traceback模块,该模块用于捕获并打印异常
try: 1/0 except Exception,e: traceback.print_exc() # Traceback (most recent call last): # File "D:/PyCharm Community Edition 2017.1.5/PycharmProjects/Learning-01/learn-01.py", line 75, in <module> # 1/0 # ZeroDivisionError: integer division or modulo by zero
然而还是并没有什么用,得不到预期结果
403
Forbidden
Cookie的使用:
1、保存cookie到变量
# import urllib2 # import cookielib # #声明一个cookiejar对象实例来保存cookie # cookie = cookielib.CookieJar() # #创建cookie处理器 # handler = urllib2.HTTPCookieProcessor(cookie) # #构建opener # opener = urllib2.build_opener(handler) # #传入request # response = opener.open('http://www.baidu.com') # for item in cookie: # print 'Name = ',item.name # print 'Value = ',item.value
Name = BAIDUID Value = B07B663B645729F11F659C02AAE65B4C:FG=1 Name = BAIDUPSID Value = B07B663B645729F11F659C02AAE65B4C Name = H_PS_PSSID Value = 12527_11076_1438_10633 Name = BDSVRTM Value = 0 Name = BD_HOME Value = 0
2、保存cookie到本地
filename = 'cookie.txt' #声明一个MozillaCookieJar对象实例来保存cookie,之后写入文件 ''' This class differs from CookieJar only in the format it uses to save and load cookies to and from a file. This class uses the Mozilla/Netscape `cookies.txt' format. ''' cookie = cookielib.MozillaCookieJar(filename) #利用urllib2库的HTTPCookieProcessor对象来创建cookie处理器 handler = urllib2.HTTPCookieProcessor(cookie) #通过handler来构建opener opener = urllib2.build_opener(handler) #创建一个请求,原理同urllib2的urlopen response = opener.open("http://www.baidu.com") #保存cookie到文件 cookie.save(ignore_discard=True, ignore_expires=True)
cookie.txt中的内容
# Netscape HTTP Cookie File # http://curl.haxx.se/rfc/cookie_spec.html # This is a generated file! Do not edit. .baidu.com TRUE / FALSE 3669689570 BAIDUID F22129FBCD4334DCB6A4DD8AE95E03DC:FG=1 .baidu.com TRUE / FALSE 3669689570 BIDUPSID F22129FBCD4334DCB6A4DD8AE95E03DC .baidu.com TRUE / FALSE H_PS_PSSID 1425_21118 .baidu.com TRUE / FALSE 3669689570 PSTM 1522205924 www.baidu.com FALSE / FALSE BDSVRTM 0 www.baidu.com FALSE / FALSE BD_HOME 0
3、从文件中获取cookie并访问
# import cookielib # import urllib2 # cookie = cookielib.MozillaCookieJar() # cookie.load('cookie.txt',ignore_discard=True,ignore_expires=True) # opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie)) # req = urllib2.Request('http://www.baidu.com') # response = opener.open(req) # print response.read()
4、利用cookie模拟网站登录
import urllib import urllib2 import cookielib filename = 'cookie.txt' cookie = cookielib.MozillaCookieJar(filename) opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie)) #输入你自己的账号 postdata = urllib.urlencode({'id':'xxxx','pwd':'xxxx'}) loginurl = 'https://www.zhihu.com/signup?next=%2F' result = opener.open(loginurl,data=postdata) cookie.save(ignore_expires=True,ignore_discard=True) #打开编辑个人信息的页面 inputurl = 'https://www.zhihu.com/people/edit' response = opener.open(inputurl) print response.read()
结果如下,讲道理,我没想到这么长的- 。 -
<!doctype html> <html lang="zh" data-hairline="true" data-theme="light"><head><meta chars 。。。。后面太长了我就不粘了