一,urllib.request
1.1 urllib.request.urlopen
request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
参数含义:
url:打开一个url,该url可以是一个字符串或者一个 Request 对象
data:参数必须是一个字节对象 ,该对象指明发送到服务器的附加数据。如果不需要发送数据,可以是None]
timeout:可选的参数 timeout 参数在秒的级别规定了一个连接尝试的阻塞等待时间(如果没有指定该参数,全局的默认的超时时间将被启用),这个参数实际上只对http,https,ftp链接有效
cafile和capath:可选的 cafile 和 capath 参数用来为https请求指明一套可信的CA证书。cafile 必须是包含了一套证书的单独的文件,capath则应该指定这些证书文件的目录。
ssl.SSLContext.load_verify_locations()函数中可以找到更多信息
context:如果 context 参数被指定,它必须是一个带有各样SLL选项的ssl.SSLContext实例
cadefault:参数已经被弃用,可以不用管了。
接下来让我看看怎么应用
我们使用 urllib.request.urlopen() 去请求百度贴吧,并获取到它页面的源代码。
import urllib.request
url = "http://tieba.baidu.com"
response = urllib.request.urlopen(url)
html = response.read() # 获取到页面的源代码
print(html.decode('utf-8')) # 转化为 utf-8 编码
使用 data 参数提交数据,在请求某些网页时需要携带一些数据,我们就需要使用到 data 参数params 需要被转码成字节流。而 params 是一个字典。我们需要使用urllib.parse.urlencode() 将字典转化为字符串。再使用 bytes() 转为字节流。***后使用 urlopen() 发起请求,请求是模拟用 POST 方式提交表单数据。
import urllib.parse
import urllib.request
url = "http://xx.xx.xx.xx/chitchat"
params = { "session":"1111","question":"你好" }
data = bytes(urllib.parse.urlencode(params), encoding='utf8')
response = urllib.request.urlopen(url, data=data)
print(response.read().decode('utf-8'))
1.2 urllib.request.Request
由上我们知道利用 urlopen() 方法可以发起简单的请求。但这几个简单的参数并不足以构建一个完整的请求,如果请求中需要加入headers(请求头)、指定请求方式等信息,我们就可以利用更强大的Request类来构建一个请求。
按照国际惯例,先看下 Request 的构造方法:
urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
url: 参数是请求链接,这个是必传参数,其他的都是可选参数。
data: 参数跟 urlopen() 中的 data 参数用法相同。
headers: 参数是指定发起的 HTTP 请求的头部信息。headers 是一个字典。它除了在 Request 中添加,还可以通过调用 Request实例的 add_header() 方法来添加请求头。
origin_req_host: 参数指的是请求方的 host 名称或者 IP 地址。
unverifiable: 参数表示这个请求是否是无法验证的,默认值是False。意思就是说用户没有足够权限来选择接收这个请求的结果。例如我们请求一个HTML文档中的图片,但是我们没有自动抓取图像的权限,我们就要将 unverifiable 的值设置成 True。
method: 参数指的是发起的 HTTP 请求的方式,有 GET、POST、DELETE、PUT等
接下来看一个demo吧:
import urllib.parse
import urllib.request
url = 'https://fanyi.baidu.com/'
headers = {
'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
}
values = {
'from': 'zh',
'to':'en',
'query':'肥猪',
'transtype':'translang',
'simple_means_flag':'3'
}
data = urllib.parse.urlencode(values).encode("utf-8")
request = urllib.request.Request(url,data,headers)
response = urllib.request.urlopen(request).read().decode("utf-8")
print(response)
1.3 urllib.request.install_opener(opener)
urllib.request.build_opener([handler, ...])
urllib.request.ProxyHandler(proxies=None)
在抓取一个网站的信息时,如果我们进行频繁的访问,就很有可能被网站检测到而被屏蔽,解决这个问题的方法就是使用ip代理 。在我们接入因特网进行上网时,我们的电脑都会被分配一个全球******地ip地址供我们使用,而当我们频繁访问一个网站时,网站也正是因为发现同一个ip地址访问多次而进行屏蔽的,所以这时候如果我们使用多个ip地址进行随机地轮流访问,这样被网站检测的概率就很小了,这时候如果我们再使用多个不同的headers,这时候就有多个ip+主机的组合,访问时被发现率又进一步减小了
步骤:
1、ProxyHandler类可以使用ip代理访问网页
proxy_support = urllib.request.ProxyHandler({}),其中参数是一个字典{‘类型’:'代理ip:端口号'}
2、定制、创建一个opener
opener = urllib.request.build_opener(proxy_support)
3、安装opener
urllib.request.install_opener(opener)
调用默认的opener
opener.open(url)
对于没有设置反爬虫机制的网站,我们只需要直接像上面那样引入ProxyHandler类进行处理,不需要考虑模仿浏览器
接下来看段例子:
import urllib.request
url="https://www.baidu.com"
for i in range(0,10000):
html = urllib.request.urlopen(url)
print(html.info())
print(i)
上面程序行351行就出错了这是由于我们在访问的时候,网站会记下我们的ip,当我们的ip访问量在一段时间内超过网站设定的上限值的时候,这个请求就会被拒绝了
#coding:utf-8
from urllib.request import Request
from urllib.request import urlopen
import urllib
import random
def gethtml(url,proxies):
proxy = random.choice(proxies)
proxy_support = urllib.request.ProxyHandler({"http":proxy})
opener = urllib.request.build_opener(proxy_support)
urllib.request.install_opener(opener)
html = urlopen(url)
return html
url = "https://www.baidu.com"
proxies=["101.53.101.172:9999","171.117.93.229:8118","119.251.60.37:21387","58.246.194.70:8080"]
for i in range(100):
try:
html = gethtml(url,proxies)
print(html.info())
print(i)
except:
print("故障")