非常明显,技术已经超越我们的人性。
——阿尔伯特·爱因斯坦(Albert Einstein)
python
爬虫之旅之第一站~~
首先讲一下urllib
库,他是python内置的一个http
请求库,他有以下主要的四个模块:
urllib.request
请求模块,我们通过他来模拟发送一个请求
urllib.error
异常处理模块
urllib.parse
url
解析模块,可以对url
进行拆分,合并等操作
urllib.robotparser
robots.txt
解析模块,主要是对网站的robots.txt
文件进行解析
下面我们就来讲解一下urllib
库中的各种使用情况:
urlopen
函数:
urllib.request.urlopen(url,data=None,[timeout])
urlopen
函数中的常见的参数有url
,data
和timeout
,url
参数是传入网站的url
,data
参数主要是用来传入一些其他的数据,timeout
是用于超时的数据。
下面看代码:
1 2 3
| import urllib.request response=urllib.request.urlopen("http://aisleep.xyz") print(response.read().decode('utf-8'))
|
其中.read()
是获取response
的内容,因为一开始是bytes
数据,所以才要再用.decode('utf-8')
将其转为字符串。这个是request
的一个get
的请求。
接着看:
1 2 3 4 5 6
| import urllib.parse import urllib.request
data=bytes(urllib.parse.urlencode({'word': 'hello'}),encoding='utf8') response=urllib.request.urlopen('http://httpbin.org',data=data) print(response.read())
|
这里传入了个data
,且必须是bytes
类型。其中调用urlencode
方法传入所需要的字典,后又定义了一个编码方式。这就是post
请求。
下面再看一下使用timeout
参数的代码:
1 2 3 4 5 6 7 8 9 10
| import urllib.request import socket import urllib.error
try: response=urllib.request.urlopen('http://httpbin.org/get',timeout=1) print(response.read()) except urllib.error.URLError as e: if isinstance(e.reason,socket.timeout): print("time out")
|
这里是使用了一个try-except
处理异常,还设置了一个timeout
参数,还有涉及到了一些error
等,这个后面会有讲解。
下面我们再来看看,urlopen
的响应类型(一般常用的有:状态码,响应头,响应体):
代码一:
1 2 3 4
| import urllib.request response=urllib.request.urlopen('http://baidu.com') print(type(response))
|
代码二:
1 2 3 4 5 6 7
| import urllib.request response=urllib.request.urlopen('https://baidu.com') print(response.status) print(response.getheaders()) print(response.getheader('Server')) print(response.read().decode('utf-8'))
|
代码一中是返回了response
的类型是什么,代码二中第3行是返回的状态码,一般请求成功状态码就是200
第4行是返回的响应头的全部信息,第5行则是返回的是响应头中的Server
参数的信息,第6行则是使用了常用的read
方法,来获取响应体的内容。
代码一:
1 2 3 4
| import urllib.request request=urllib.request.Request('http://aisleep.xyz') response=urllib.request.urlopen(request) print(response.read().decode('utf-8'))
|
代码二:
1 2 3 4 5 6 7 8 9 10
| from urllib import request,parse url="http://httpbin.org/post" dict={ 'name':'lifan' } data=bytes(parse.urlencode(dict),encoding='utf8') req=request.Request(url=url,data=data,method='POST') req.add_header('User-Agent','Mozilia/4.0(compatible;MSIE 5.5;Windows NT)') response=request.urlopen(req) print(response.read().decode('utf-8'))
|
这里代码二是将url
,data
,header
一起传给Request
对象,然后再使用urlopen
函数。第8行是传入了一个header
,可以用特殊的add_header
函数,也可以将其构造一个和这里的dict
一样的字典传给Request
。
通过Request
对象可以将我们需要传入的请求方式,请求头,请求体等参数构造成一各整体,传给Request
对象,发送给服务器。这里使用Request
对象,再调用urlopen
函数的方法相比于直接使用urlopen
函数的好处就是可以传入更多类型的参数。不单单只是url
,timeout
,data
等了。
1 2 3 4 5 6 7 8
| import urllib.request proxy_handler=urllib.request.ProxyHandler({ 'https': 'https://127.0.0.1:9743', 'http': 'http://127.0.0.1:9743' }) opener=urllib.request.build_opener(proxy_handler) response=opener.open('http://www.google.com') print(response.read())
|
这里稍后再细讲
获取cookie
1 2 3 4 5 6 7
| import urllib.request,http.cookiejar cookie=http.cookiejar.CookieJar() hander=urllib.request.HTTPCookieProcessor(cookie) opener=urllib.request.build_opener(hander) response=opener.open('http://www.baidu.com') for item in cookie: print(item.name+"="+item.value)
|
cookie
保存:
1 2 3 4 5 6 7 8
| import http.cookiejar,urllib.request filename="cookie.txt" cookie=http.cookiejar.MozillaCookieJar(filename) handler=urllib.request.HTTPCookieProcessor(cookie) opener=urllib.request.build_opener(handler) response=opener.open("http://www.baidu.com") cookie.save(ignore_discard=True,ignore_expires=True)
|
1 2 3 4 5 6 7 8
| import http.cookie,urllib.request filename ='cookie.txt' cookie=http.cookiejar.LWPCookieJar(filename) handler=urllib.request.HTTPCookieProcessor(cookie) opener=urllib.request.build_opener(handler) response=opener.open('http://www.baidu.com') cookie.save(ignore_discard=True,ignore_expires=True)
|
1 2 3 4 5 6 7
| import http.cookiejar,urllib.request cookie=http.cookiejar.LWPCookiejar() cookie.load('cookie.txt',ignore_discard=True,ignore_expires=True) handler=urllib.request.build_opener(handler) response=opener.open('http://www.baidu.com') print(response.read().decode('utf-8'))
|
cookie
这里的使用,后面再细讲。
1 2 3 4 5 6 7 8 9
| from urllib import request,error try: response=request.urlopen('http://www.baidu.com') except error.HTTPError as e: print(e.reason,e.code,e.headers,sep='\n') except error.URLError as e: print(e.reason) else: print('Request.Successfully')
|
1 2 3
| from urlib.parse import urlparse result=urlparse('http://www.baidu.com/index.html;user?id=5#comment') print(result)
|
urlparse
模块主要是对url
进行解析,这个代码的输出信息是:
ParseResult(scheme='http',netloc='www.baidu.com',path='/index.html',params='user',query='id5',fragment='comment')
再看:
1 2 3
| from urlib.parse import urlparse result=urlparse('http://www.baidu.com/index.html;user?id=5#comment',scheme='https') print(result)
|
这个代码的输出信息则是:
ParseResult(scheme='http',netloc='www.baidu.com',path='/index.html',params='user',query='id5',fragment='comment')
可以看到,我们指定的协议类型,如果默认协议存在则不会被我们指定的协议所改变。
再看:
1 2
| from urllib.parse import urlparse result=urlparse('http://www.baidu.com/index.html;user?id=5#comment',allow_fragments=False)
|
这个代码的输出信息则是:
ParseResult(scheme='http',netloc='www.baidu.com',path='/index.html',params='user',query='id=5#comment',fragment='')
可见,当我们指定allow_fragment=False
的时候,fragment
的内容就会被拼接到前面的query
里面去。如果连前面的query
也没有呢?fragment
里面的内容会继续拼接到前面的地方。
1 2 3
| from urllib.parse import urlunparse data=['http','www.baidu.com','index.html','user','a=6','comment'] print(urlunparse(data))
|
这个代码的输出信息则是:
http://www.baidu.com/index.html;user?a=6#comment
1 2 3 4 5 6
| from urllib.parse import urljoin print(urljoin('http://www.baidu.com','https://www.google.com/faq.html')) print(urljoin('http://www.baidu.com','https://www.baidu.com')) print(urljoin('http://www.baidu.com','http://www.baidu.com/FAQ.html?question=2')) print(urljoin('http://www.baidu.com','?category=1'))
|
这个代码的运行结果是:
1 2 3 4
| https://www.google.com/faq.html https://www.baidu.com http://www.baidu.com/FAQ.html?question=2 http://www.baidu.com?category=1
|
我们从中可以知道,urljoin
函数,泛泛的理解就是:在前者后者都有的情况下,后者的内容会覆盖前者,前者没有后者有的时候,也是为后者的内容,如果前者有,后者内容没有就以前者为准。
urlencode
函数,将字典对象转换成get
请求参数
1 2 3 4 5 6 7 8
| from urllib.parse import urlencode params={ 'name':'lifan', 'age':23 } base_url='http://www.baidu.com' url=base_url+urlencode(params) print(url)
|
运行结果是:http://www.baidu.comname=lifan&age=23