Python养成记

23、网络请求:如何利用 urllib 包获取网络资源

2022-04-07  本文已影响0人  魔方宫殿
Life is short, you need Python!

上集回顾:

  1. 句法错误
  2. 异常
  3. 异常处理
  4. 触发异常
  5. finally子句

上集学习了Python代码编写过程中常见的一些错误和异常,熟悉这些知识有助于出错时快速定位错误原因。
本集学习网络请求的相关知识。现在是一个网络时代,互联网上可以说是包罗万象,只有你想不到的没有你找不到的。但互联网上最多的也是无用信息,有人甚至把互联网比作垃圾堆积场。所以要想利用好网络,就要学会利用搜索引擎等相关工具,以便在海量的信息出检索出有价值的信息。用Python程序自动收集整理目标信息也是一个很好的手段。要想检索网络信息,第一步肯定是要获取网络信息,而怎么获取网络信息就是本集的主角:urllib。

一、GET
urllib.request 是用于获取 URL (统一资源定位符)的 Python 模块。它以 urlopen 函数的形式提供了一个非常简单的接口,能用不同的协议获取 URL。
urllib.request 最简单的使用方式如下所示:

import urllib.request

with urllib.request.urlopen('http://www.baidu.com') as response:
    html = response.read()
    print(html[:300])
    f = open('baidu.html', 'w', encoding='utf-8')
    f.write(html.decode('utf-8'))
    f.flush()

保存到test.py,然后命令行执行:

$ python test.py
b'<!DOCTYPE html><!--STATUS OK--><html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta content="always" name="referrer"><meta name="theme-color" content="#ffffff"><meta name="description" content="\xe5\x85\xa8\xe7\x90\x83\xe9\xa2\x86\xe5\x85\x88\xe7'

另外还得到一个baidu.html文件,双击在浏览器打开,就是百度的界面。这就是urllib已经把百度首页的html代码获取并保存到本地了。

二、POST
有时需要向某个 URL 发送数据,通常此 URL 会指向某个CGI(通用网关接口)脚本或其他 web 应用。对于 HTTP 而言,这通常会用所谓的 POST 请求来完成。当要把 Web 页填写的 HTML 表单提交时,浏览器通常会执行此操作。但并不是所有的 POST 都来自表单:可以用 POST 方式传输任何数据到自己的应用上。对于通常的 HTML 表单,数据需要以标准的方式编码,然后作为 data 参数传给 Request 对象。编码过程是用 urllib.parse库的函数完成的:

import urllib.parse
import urllib.request

url = 'http://www.someserver.com/cgi-bin/register.cgi'
values = {'name' : 'Michael Foord',
          'location' : 'Northampton',
          'language' : 'Python' }

data = urllib.parse.urlencode(values)
data = data.encode('ascii') # data should be bytes
req = urllib.request.Request(url, data)
with urllib.request.urlopen(req) as response:
   the_page = response.read()

三、HTTP 头部信息
下面介绍一个具体的 HTTP 头部信息,以此说明如何在 HTTP 请求加入头部信息。

有些网站不愿被程序浏览到,或者要向不同的浏览器发送不同版本的网页。默认情况下,urllib 将自身标识为“Python-urllib/xy”(其中 xy 是 Python 版本的主、次版本号,例如 Python-urllib/2.5),这可能会让网站不知所措,或者干脆就使其无法正常工作。浏览器是通过头部信息 User-Agent 来标识自己的。在创建 Request 对象时,可以传入字典形式的头部信息。以下示例将生成与之前相同的请求,只是将自身标识为某个版本的 Internet Explorer:

import urllib.parse
import urllib.request

url = 'http://www.someserver.com/cgi-bin/register.cgi'
user_agent = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)'
values = {'name': 'Michael Foord',
          'location': 'Northampton',
          'language': 'Python' }
headers = {'User-Agent': user_agent}

data = urllib.parse.urlencode(values)
data = data.encode('ascii')
req = urllib.request.Request(url, data, headers)
with urllib.request.urlopen(req) as response:
   the_page = response.read()

四、错误处理
如果 urlopen 无法处理响应信息,就会触发 URLError 。尽管与通常的 Python API 一样,也可能触发 ValueErrorTypeError 等内置异常。
HTTPErrorURLError 的子类,当 URL 是 HTTP 的情况时将会触发。
上述异常类是从 urllib.error 模块中导出的。

  1. URLError
    触发 URLError 的原因,通常是网络不通(或者没有到指定服务器的路由),或者指定的服务器不存在。这时触发的异常会带有一个 reason 属性,是一个包含错误代码和文本错误信息的元组。
    例如:
>>> req = urllib.request.Request('http://www.pretend_server.org')
>>> try: urllib.request.urlopen(req)
... except urllib.error.URLError as e:
...     print(e.reason)      
...
(4, 'getaddrinfo failed')
  1. HTTPError
    从服务器返回的每个 HTTP 响应都包含一个数字的 “状态码”。有时该状态码表明服务器无法完成该请求。默认的处理函数将会处理这其中的一部分响应。如若响应是“redirection”,这是要求客户端从另一 URL 处获取数据,urllib 将会自行处理。对于那些无法处理的状况,urlopen 将会引发 HTTPError 。典型的错误包括:“404”(页面无法找到)、“403”(请求遭拒绝)和“401”(需要身份认证)。
    全部的 HTTP 错误码请参阅 RFC 2616
    HTTPError 实例将包含一个整数型的“code”属性,对应于服务器发来的错误。
    默认处理函数会自行处理重定向(300 以内的错误码),而且 100--299 的状态码表示成功,因此通常只会出现 400--599 的错误码。
    可以如下处理:
from urllib.request import Request, urlopen
from urllib.error import URLError
req = Request(someurl)
try:
    response = urlopen(req)
except URLError as e:
    if hasattr(e, 'reason'):
        print('We failed to reach a server.')
        print('Reason: ', e.reason)
    elif hasattr(e, 'code'):
        print('The server couldn\'t fulfill the request.')
        print('Error code: ', e.code)
else:
    # everything is fine

本集总结:

  1. GET请求
  2. POST请求
  3. HTTP 头部信息
  4. 错误处理

下集见

上一篇下一篇

猜你喜欢

热点阅读