python 进行网络编程,可以使用 python 的内置库: urllib 库。urllib 库分为以下几个模块:
urllib.request 负责打开和读取 URL,是 urllib 库最重要也最常用的模块。其定义了一些打开 URL 的函数和类,包含授权验证、重定向、浏览器 cookkies 等。它可以模拟浏览器的一个请求发起过程。
request 最简单的用法就是模拟浏览器发送一个请求,并获取应答。
from urllib.request import urlopen
url = 'https://www.baidu.com' # 设置请求地址
resp = urlopen(url) # 发送请求,并获得应答
print(resp.read().decode('utf-8') # 查看应答信息,因为默认是以二进制查看,所以需要解码为 utf-8
这样就获取到了应答信息。输出的是 html 文本,也可以写到文件中使用浏览器打开。
with open('mybaidu.html', 'w', encoding='utf-8') as file:
file.write(resp.read().decode('utf-8'))
urlopen 函数的全部参数如下:
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
发送请求后无论如何会收到一个状态码,这个状态码会表示该请求的响应状态。例如 200 成功、404 页面未找到等。
import urllib.request
myURL1 = urllib.request.urlopen("https://www.runoob.com/")
print(myURL1.getcode()) # 200
try:
myURL2 = urllib.request.urlopen("https://www.runoob.com/no.html")
except urllib.error.HTTPError as e:
if e.code == 404:
print(404) # 404
具体的状态码和含义可以看这里:
我们抓取网页一般需要对 headers(网页头信息)进行模拟,这时候需要使用到 urllib.request.Request 类:
class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
import urllib.request
url = 'https://www.runoob.com/?s=' # 菜鸟教程搜索页面
keyword = 'Python 教程'
key_code = urllib.request.quote(keyword) # 对请求进行编码
url_all = url + key_code
header = {
'User-Agent': 'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
} # 头部信息
request = urllib.request.Request(url_all, headers=header)
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))
上面的例子是将请求头以实参形式传入,也可以使用 Request.add_header() 方法添加请求头信息。
import urllib.request
url = 'http://www.baidu.com/'
req = urllib.request.Request(url)
req.add_header("User-Agent",'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36')
html = urllib.request.urlopen(req).read()
因为 Request 类的数据信息必须是字节型的,所以需要使用 urllib.parse 进行编码
import urllib.request
import urllib.parse
url = 'https://www.runoob.com/try/py3/py3_urllib_test.php' # 提交到表单页面
data = {'name':'RUNOOB', 'tag' : '菜鸟教程'} # 提交数据
header = {
'User-Agent':'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
} #头部信息
data = urllib.parse.urlencode(data).encode('utf8') # 对参数进行编码,解码使用 urllib.parse.urldecode
request=urllib.request.Request(url, data, header) # 请求处理
response=urllib.request.urlopen(request).read() # 读取结果
print(response.decode('utf-8'))
使用代理服务器分为5步:设置代理、创建代理、应用代理、创建 Request 对象、发送访问请求:
import urllib.request
# 设置代理
httpproxy_handler = urllib.request.ProxyHandler({'https': 'daili.com:8888'})
# 创建代理
opener = urllib.request.build_opener(httpproxy_handler)
# 将代理应用到全局
urllib.request.install_opener(opener)
# 创建 request 对象
request = urllib.request.Request(url)
# 发送请求
html = urllib.request.urlopen(request).read()
urllib.error 模块为 urllib.request 所引发的异常定义了异常类,基础异常类是 URLError。urllib.error 包含了两个方法,URLError 和 HTTPError。
URLError 是 OSError 的一个子类,用于处理程序在遇到问题时会引发此异常(或其派生的异常),包含的属性 reason 为引发异常的原因。
HTTPError 是 URLError 的一个子类,用于处理特殊 HTTP 错误,例如作为认证请求的时候,包含的属性 code 为 HTTP 的状态码, reason 为引发异常的原因,headers 为导致 HTTPError 的特定 HTTP 请求的 HTTP 响应头。
例如对不存在的页面抓取并处理异常:
import urllib.request
import urllib.error
myURL1 = urllib.request.urlopen("https://www.runoob.com/")
print(myURL1.getcode()) # 200
try:
myURL2 = urllib.request.urlopen("https://www.runoob.com/no.html")
except urllib.error.HTTPError as e:
if e.code == 404:
print(404) # 404
import urllib.request
import urllib.error
def download_with_retry(url,num_retries):
print('下载中 ',url)
try:
# 下载网页并获取网页的 html 内容
html = urllib.request.urlopen(url).read()
except urllib.erroe.URLError as e:
if hasattr(e, 'reason'):
print('下载失败')
print('失败原因:', e.reason)
if hasattr(e, 'code'):
print('服务器不能完成请求')
print('错误代码:', e.code)
if num_retries>0 and 500<=e.code<600:
return download_with_retries(url,num_retries-1)
return html
urllib.parse 用于解析 URL,格式如下:
urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)
from urllib.parse import urlparse
o = urlparse("https://www.runoob.com/?s=python+%E6%95%99%E7%A8%8B")
print(o)
# 输出结果
# ParseResult(scheme='https', netloc='www.runoob.com', path='/', params='', query='s=python+%E6%95%99%E7%A8%8B', fragment='')
也可以使用 urllib.parse.urlencode() 将数据进行编码,例如使用 urllib.request.Request 对象发送带数据的请求时的例子。
urllib.robotparser 用于解析 robots.txt 文件。robots.txt(统一小写)是一种存放于网站根目录下的 robots 协议,它通常用于告诉搜索引擎对网站的抓取规则。
requests 库也是 python 用于网络编程的一个库,由于是第三发库,所以需要进行安装。
import requests
url = 'https://www.sogou.com/web?query=周杰伦'
resp = requests.get(url)
print(resp) # 执行结果: <Response [200]>
print(resp.text) # 执行结果为页面内容
请求头中有一种设置:Connection: keep-alive ,如果不显式的断开连接,则会长时间占用TCP连接。通常可以发送一个请求报文,设置 Connection: close 。但是实际上其实可以直接对连接对象进行关闭。
resp.close() # 关闭 resp 连接
上一个例子中,访问 https://www.sogou.com/web?query=周杰伦 时可以发现,浏览器可以正常访问,而 python 程序则不行。所以需要设置请求头,模拟普通浏览器发送请求来访问页面。
requests 库的请求头写在一个字典内,并且在发送请求时需要传递至方法实参。
import requests
url = 'https://www.sogou.com/web?query=周杰伦'
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36"
}
resp = requests.get(url, headers=header)
print(resp.text)
这里请求头里的 User-Agent 信息可以使用浏览器调试工具获取。
在爬虫测试中,如果被反爬了,则很大几率是出在请求头的 User-Agent 里。我们可以先查看下请求头信息。
import requests
url = 'https://www.sogou.com/web?query=周杰伦'
resp = requests.get(url)
print(resp.request.headers) # 输出请求头信息
发送 post 请求使用 requests.post() 方法。发送的数据是以字典形式传入实参。
import requests
url = 'https://fanyi.baidu.com/sug'
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36"
}
d = {'kw': 'dog'}
resp = requests.post(url, headers=header, data=d)
print(resp.json()) # 以 json 字符串形式输出
get 请求的参数除了可以直接写在 url 里,还可以使用附加方式发送:
import requests
url = 'https://movie.douban.com/j/chart/top_list'
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36"
}
param = {
'type': '24',
'interval_id': '100:90',
'action': '',
'start': 0,
'limit': 20
}
resp = requests.get(url, headers=header, params=param)
print(resp.request.url)
print(resp.json())
requests 使用代理和 urllib 使用代理类似,将代理字典(包含协议、地址+端口)以实参形式传入请求的形参 proxies 即可。
resp = requests.get(url, headers=head, proxies=proxy)
不管使用 get 还是 post 发送了请求后,会返回一个 Response 对象,可以通过此对象的一些属性和方法获得我们想要的数据:
r = requests.get('https://www.baidu.com')