一 、什么是爬虫
模拟客户端,访问网站服务器,爬虫从服务器响应给客户端的网页内容中解析有用信息并保存到本地。
二、爬虫执行的流程
(1)请求网页
(2)解析网页信息
(3)保存内容
三、Python爬虫所用到的库
1.请求网页的库
requests
urllib3
selenium(模拟浏览器)
2.解析网页信息的库
re(正则表达式)
BeautifulSoup:BS4
Xpath
3.保存内容到本地
csv txt
下载图片
四、urllib
urllib是python内置HTTP请求库
urllib.request
请求模块
urllib.error
异常处理模块
urllib.parse
url解析模块
urllib.robotparser
robots.txt解析模块
1.请求
直接使用urlopen()
import urllib.request
''''data字段为空,get请求'''
response = urllib.request.urlopen('http://www.baidu.com')
print(response.read().decode('utf-8'))
import urllib.parse
import urllib.request
"""指定data字段,为post请求"""
data = bytes(urllib.parse.urlencode({'word':'hello'}),encoding='utf8')
response = urllib.request.urlopen('http://httpbin.org/post',data=data)
print(response.read())
使用request对象
from urllib import request, parse
url = 'http://httpbin.org/post'
headers = {
'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
'Host': 'httpbin.org'
}
dict = {
'name': 'Germey'
}
data = bytes(parse.urlencode(dict), encoding='utf8')
req = request.Request(url=url, data=data, headers=headers, method='POST')
response = request.urlopen(req)
print(response.read().decode('utf-8'))
Handler子类继承这个BaseHandler
类,举例如下。
HTTPDefaultErrorHandler
:用于处理HTTP响应错误,错误都会抛出HTTPError类型的异常。
HTTPRedirectHandler
:用于处理重定向。
HTTPCookieProcessor
:用于处理Cookies。
ProxyHandler
:用于设置代理,默认代理为空。
HTTPPasswordMgr
:用于管理密码,它维护了用户名和密码的表。
HTTPBasicAuthHandler
:用于管理认证,如果一个链接打开时需要认证,那么可以用它来解决认证问题。
另一个比较重要的类就是OpenerDirector
,我们可以称为Opener
。
我们需要实现更高级的功能,所以需要深入一层进行配置,使用更底层的实例来完成操作,所以这里就用到了Opener
。
Opener
可以使用open()
方法,返回的类型和urlopen()
如出一辙。那么,它和Handler
有什么关系呢?简而言之,就是利用Handler
来构建Opener
。
1.1 验证
from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
from urllib.error import URLError
username = 'username'
password = 'password'
url = 'http://localhost:5000/'
p = HTTPPasswordMgrWithDefaultRealm()
p.add_password(None, url, username, password)
auth_handler = HTTPBasicAuthHandler(p)#实例化HTTPBasicAuthHandler对象,其参数是HTTPPasswordMgrWithDefaultRealm对象
opener = build_opener(auth_handler)#利用这个Handler并使用build_opener()方法构建一个Opener
try:
result = opener.open(url)#利用Opener的open()方法打开链接,就可以完成验证了
html = result.read().decode('utf-8')
print(html)
except URLError as e:
print(e.reason)
1.2 代理
from urllib.error import URLError
from urllib.request import ProxyHandler, build_opener
#ProxyHandler,其参数是一个字典,键名是协议类型(比如HTTP或者HTTPS等),键值是代理链接,可以添加多个代理
proxy_handler = ProxyHandler({
'http': 'http://127.0.0.1:9743',
'https': 'https://127.0.0.1:9743'
})
opener = build_opener(proxy_handler)
try:
#利用这个Handler及build_opener()方法构造一个Opener,之后发送请求即可。
response = opener.open('https://www.baidu.com')
print(response.read().decode('utf-8'))
except URLError as e:
print(e.reason)
1.3 cookies
获取网站上的cookie
import http.cookiejar, urllib.request
cookie = http.cookiejar.CookieJar()#声明一个CookieJar对象
handler = urllib.request.HTTPCookieProcessor(cookie)#利用HTTPCookieProcessor来构建一个Handler
opener = urllib.request.build_opener(handler)#build_opener()方法构建出Opener
response = opener.open('http://www.baidu.com')
for item in cookie:
print(item.name+"="+item.value)
这段代码是输出文本,下面这段代码可以将cooike保存到文件
filename = 'cookies.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)
LWPCookieJar
同样可以读取和保存Cookies,但是保存的格式和MozillaCookieJar不一样,它会保存成libwww-perl(LWP)格式的Cookies文件。
cookie = http.cookiejar.LWPCookieJar(filename)
读取本地cookie文件
cookie = http.cookiejar.LWPCookieJar()
#这里调用load()方法来读取本地的Cookies文件,获取到了Cookies的内容。不过前提是我们首先生成了LWPCookieJar格式的Cookies,并保存成文件
cookie.load('cookies.txt', ignore_discard=True, ignore_expires=True)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
print(response.read().decode('utf-8'))
2.响应
状态码,响应头
import urllib.request
response = urllib.request.urlopen('http://www.baidu.com')
print(response.status)
print(response.getheaders())
print(response.getheader('Server'))
3.处理异常
3.1 URLError
由request模块生的异常都可以通过捕获这个类来处理。
请求一个不存在的网页
from urllib import request, error
try:
response = request.urlopen('http://www.nwu.edu.cn/index.htm')
except error.URLError as e:
print(e.reason)
3.2 HTTPError
它是URLError
的子类,专门用来处理HTTP请求错误,比如认证请求失败等。它有如下3个属性。
code
:返回HTTP状态码,比如404表示网页不存在,500表示服务器内部错误等。
reason
:同父类一样,用于返回错误的原因。
headers
:返回请求头。
3.3 建议的异常处理方法
from urllib import request, error
try:
response = request.urlopen('http://cuiqingcai.com/index.htm')
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')
这样就可以做到先捕获HTTPError
,获取它的错误状态码、原因、headers等信息。如果不是HTTPError
异常,就会捕获URLError
异常,输出错误原因。最后,用else来处理正常的逻辑。
4.URL解析
urlparse,利用urlparse()方法可以将url拆分开来
urllib.parse.urlparse(urlstring,scheme='',allow_fragments=True)
from urllib.parse import urlparse
result = urlparse('http://www.baidu.com/index.html;user?id=5#comment')
print(type(result), result)
<class ‘urllib.parse.ParseResult’> ParseResult(scheme=‘http’, netloc=‘www.baidu.com’, path=’/index.html’, params=‘user’, query=‘id=5’, fragment=‘comment’)
指定协议类型:
from urllib.parse import urlparse
result = urlparse('www.baidu.com/index.html;user?id=5#comment', scheme='https')
print(result)
ParseResult(scheme=‘https’, netloc=’’, path=‘www.baidu.com/index.html’, params=‘user’, query=‘id=5’, fragment=‘comment’)
最后一个参数:allow_fragments为是否允许使用锚点链接,返回值中的fragment为空,其值将被拼接至前一个非空字段。
5. urlunparse
将url进行拼接
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
6. urljoin
from urllib.parse import urljoin
print(urljoin('http://www.baidu.com', 'FAQ.html'))
print(urljoin('http://www.baidu.com', 'https://www.nwu.edu.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://www.nwu.edu.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://www.nwu.edu.com/FAQ.html?question=2'))
print(urljoin('http://www.baidu.com?wd=abc', 'https://www.nwu.edu.com/index.php'))
print(urljoin('http://www.baidu.com', '?category=2#comment'))
print(urljoin('www.baidu.com', '?category=2#comment'))
print(urljoin('www.baidu.com#comment', '?category=2'))
http://www.baidu.com/FAQ.html
https://www.nwu.edu.com/FAQ.html
https://www.nwu.edu.com/FAQ.html
https://www.nwu.edu.com/FAQ.html?question=2
https://www.nwu.edu.com/index.php
http://www.baidu.com?category=2#comment
www.baidu.com?category=2#comment
www.baidu.com?category=2
7.urlencode
将字典对象转换为get请求参数
from urllib.parse import urlencode
params={
'name':"nwu",
'age':'119'
}
base_url = 'http://www.baidu.com?'
url = base_url + urlencode(params)
print(url)
http://www.baidu.com?name=nwu&age=119