文章目录
- urllib库
- 抓取网页
- data参数
- timeout参数
- 更灵活地配置参数
- 登录
- 代理
- Cookies
- 参考书籍
建议新入门的小伙伴先看我同一专栏的文章:用python写网络爬虫:1.基础知识
urllib库
urllib是python中一个最基础的HTTP库,一般是内置的,不需要额外下载
抓取网页
使用urllib中的request模块可以方便向服务器发送请求,以抓取目标网页的源代码。
import urllib.requests
以抓取CSDN官网为例,代码如下
import urllib.request
# 使用urllib库发送HTTP请求到指定的网站,将响应保存在response变量中。
response = urllib.request.urlopen('https://www.csdn.net/')
print(response.read())
运行上述代码,结果如下
为方便看懂,修改代码,使输出结果按utf-8解码
print(response.read().decode('utf-8'))
结果就是我们可以看到解码后的汉字了
如果想获取更多特定的信息,可以把输出改为以下命令
print(type(response)) #获取响应的类型
print(response.status) #获取响应状态码
print(response.getheaders()) #获取响应头
print(response.getheader('Server')) #获取Server信息,即服务器的搭建方式
结果示例如下
其中
- 第一行表示它是一个HTTPResponse类型的对象
- 第二行状态码为200,表示响应成功
- 下面一大段表示响应头,给出了该网站的信息
- 最后一行的Server信息就是从响应头里获取的
利用上述最基本urlopen()方法,可以完成最基本的get请求,下面演示用urlopen可选的参数去完成更多的事情
data参数
如果添加这个参数,就意味着要向服务器传送一些信息,即GET请求变为POST请求
我们将目标网址改为http://httpbin.org/post,这是一个专门测试POST请求的链接
修改前文的代码,改动主要有:加载urllib库中的parse模块、添加参数data、修改目标网址。如下所示
import urllib.request
import urllib.parse
# 使用urllib库中的parse模块,将字符串转换为字节流,便于网络传输
data = bytes(urllib.parse.urlencode({'word':'hello'}),encoding='utf-8')
response = urllib.request.urlopen('http://httpbin.org/post',data=data)
print(response.read())
输出结果如下
这里我们传递了一个参数word,其值为hello,从输出结果中可以发现我们传递的参数出现在了form字段中
timeout参数
该参数的作用是设置一个超时时间(单位为秒),若服务器超过了这个时间还未响应,则返回URLError异常;若不指定该参数,则会使用默认时间。
以下是一个由于响应超时会返还异常的例子
import urllib.request
response = urllib.request.urlopen('http://httpbin.org/get',timeout=0.1)
print(response.read())
实际应用中,往往通过设置这个超时时间,让程序正常运行。原理是:如果超过这个超时时间,则跳过这部分网页的抓取。
下面是一个使用try except语句进行实现的例子
import urllib.request
import urllib.error
import socket
try:
response = urllib.request.urlopen('http://httpbin.org/get',timeout=0.1)
except urllib.error.URLError as e:
# 检查异常对象e的原因部分是否是socket.timeout类型,即是否是超时错误
if isinstance(e.reason,socket.timeout):
print('Time out')
更灵活地配置参数
仅仅使用urlopen()及其几个参数,不足以灵活地构建一个请求,我们使用request类以更方便地加入更多信息
这里更方便的意思是,我们把urlopen()方法的参数改成一个Request类型的对象,用以添加参数,如下例
import urllib.request
request = urllib.request.Request('https://www.csdn.net/')
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))
参数
- url:用于请求URL,是必传参数,其他都是可选参数
- data:用于传递(POST)请求的数据
- herders={}:即请求头
- origin_req_host:请求方的host名称或IP地址
- unverifiable:用于指示请求是否是不可验证的。默认为False,当设置为True时,表示请求的可信度无法得到验证,可能会触发一些警告。在处理一些不太可靠的网站或者资源时可能会有用。
- method:指定请求方法的类型,如:POST,GET,PUT等
举个例子:
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='utf-8')
req = request.Request(url=url,data=data,headers=headers,method='POST')
response = request.urlopen(req)
print(response.read().decode('utf-8'))
这里headers指定了User-Agent和Host,User-Agent是一种身份信息,默认值为Python-urllib,我们可以修改它以进行伪装。
比如上例伪装的是IE浏览器,设置为
MOzilla/4.0(compatible ; MSIE 5.5;Windows NT)
也可以伪装成火狐浏览器:
Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11
登录
前文提到的urlopen(),我们称作它是一个opener,是用来发送URL请求的对象。urlopen是已经写好的一个opener,包含了我们常用的请求,但如果我们想要实现更高级的功能时,需要自定义一个opener,以实现需求。在这个过程中,我们要构建一个handler,可以把它理解成一个工具:针对不同的需求,我们定制不同的handler,opener使用这个handler工具就可以实现我们的需求。
访问有些网站时,需要进行登录,这时我们应在请求中添加用户名和密码的信息,这是urlopen方法不包含的,需要自定义opener。
以下两个类可以帮助实现登录功能
HTTPPasswordMgrWithDefaultRealm 类:允许你为特定的 URL 和域名添加用户名和密码。可以避免在每个请求中都手动指定用户名和密码,提高代码的可维护性和可重用性
HTTPBasicAuthHandler 类:它负责在请求中包含适当的认证头,以便通过服务器的认证机制
from urllib.request import HTTPPasswordMgrWithDefaultRealm,HTTPBasicAuthHandler,build_opener
from urllib.error import URLError
# 这里输入目标网站的URL和你的用户名、密码
username = 'username'
password = 'password'
url = 'http://localhost:5000/'
p = HTTPPasswordMgrWithDefaultRealm()
p.add_password(None,url,username,password)
auth_handler = HTTPBasicAuthHandler(p)
opener = build_opener(auth_handler)
# 尝试使用 opener 打开指定的 URL
# 如果成功打开,则读取返回的内容并打印出来;如果发生 URLError,则打印出错误原因
try:
result = opener.open(url)
html = result.read().decode('utf-8')
print(html)
except URLError as e:
print(e.reason)
代理
可以使用ProxyHandler类在爬虫程序中添加代理,同样地,你需要自定义一个opener
from urllib.request import ProxyHandler,build_opener
from urllib.error import URLError
# 这里填写你的代理地址
proxy_handler = ProxyHandler({
'http':'http://127.0.0.1:9743',
'https':'https://127.0.0.1:9743'
})
opener = build_opener(proxy_handler)
try:
response = opener.open('https://www.baidu.com')
print(response.read().decode('utf-8'))
except URLError as e:
print(e.reason)
Cookies
Cookies是服务器储存在用户端的信息,比如用户的账户信息就可以被储存在Cookies中,以便下次访问该网站的时候不需登录即可进入到相同账户。
我们利用HTTPCookieProcessor来建立一个handler,从而获取cookies
import http.cookiejar,urllib.request
cookie = http.cookiejar.CookieJar()
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
for item in cookie:
print(item.name+"="+item.value)
输出结果如下
可以看见结果中包含了三条cookie的名称和值,我们还可以把数据储存在文件里,为生成文件,需要将CookieJar改为MozillaCookieJar,代码如下
import http.cookiejar,urllib.request
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)
要生成LWP格式的文件,则使用LWPCookieJar,只需修改
cookie = http.cookiejar.LWPCookieJar(filename)
可以用load()方法读取并利用Cookies文件,以LWP格式为例
import http.cookiejar,urllib.request
cookie = http.cookiejar. LWPCookieJar()
# 从文件 'cookies.txt' 中加载 Cookie 信息到 LWPCookieJar 对象中
# ignore_discard=True 表示即使 cookies.txt 中的 cookie 已经过期也将其保存,
# ignore_expires=True 表示即使 cookies.txt 中的 cookie 已经过期也将其保存。
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'))
基本用法介绍到这,更多详见官方文档https://docs.python.org/3/library/urllib.request.html
参考书籍
《python3 网络爬虫开发实战》崔庆才著