爬取第一个网页

0 前言

相信看了前面一篇之后,大家对 HTTP协议都有了一些了解。可能你还没完全搞懂,但是不要紧。跟着下面的内容走一遍相信你会对 HTTP协议有更深的了解,理论总是在实践之后变得更加清晰。

在进入正题之前我们先准备一下环境,首先 Python环境不能少,版本没有强制要求,但最好是 Python3。Python环境有了之后我们再来安装今天要用到的库,requests。使用下面的命令安装:

pip install requests

requests是 Python中最常用的请求库,使用 requests我们几乎可以模拟绝大多数浏览器中的请求,包括表单提交、文件上传、会话模拟等。我们来看一个示例:

import requests

r = requests.get('http://www.baidu.com/')
print(r.text)

在这个示例中我们请求了百度的首页并将收到的响应打印出来,看起来还挺简单的。接下来让我们一步一步地来学习 requests的使用。

1 post和 get方法

requests中有两个最常用的方法,requests.postrequests.get。这两个方法分别对应 HTTP中的 POST和 GET请求。并且它们还有相同的参数,参数和 HTTP中报文的对照关系如下:

  • url:url对应 HTTP报文中的 URL,表示要请求的网址。
  • data:data对应 HTTP报文中的报文体,表示 POST提交的数据。
  • prams:params对应 GET方法的参数。
  • headers:headers对应 HTTP中的请求头。

下面我们通过一些例子来进一步了解如何利用这些参数来构造我们需要的请求。

import requests

# 普通的 GET请求
r = requests.get('http://www.geebos.cn/blog/test')
print('1:', r.text)

# 带参数的 GET请求
params = {
    'arg': 'myarg',
}
r = requests.get('http://www.geebos.cn/blog/test', params=params)
# 上面的请求和下面这个请求等价,因为 GET的参数经过处理后会添加到 URL结尾,并用问号 ”?“将参数和 URL区分开来
r = requests.get('http://www.geebos.cn/blog/test?arg=myarg')
print('2:', r.text)


# 普通的 POST请求
r = requests.post('http://www.geebos.cn/blog/test')
print('3:', r.text)

# 带参数的 POST请求
data = {
    'arg': 'myarg'
}
r = requests.post('http://www.geebos.cn/blog/test', data=data)
print('4:', r.text)

# 设置请求头
headers = {
    'user-agent': 'requests spider'
}
r = requests.post('http://www.geebos.cn/blog/test', headers=headers)
print('5:', r.text)

执行上面的代码之后我们可以看到下面的输出:

1: 你发送的是 GET请求,参数是: {},user-agent=python-requests/2.25.1
2: 你发送的是 GET请求,参数是: {'arg': ['myarg']},user-agent=python-requests/2.25.1
3: 你发送的是 POST请求,参数是: {},user-agent=python-requests/2.25.1
4: 你发送的是 POST请求,参数是: {'arg': ['myarg']},user-agent=python-requests/2.25.1
5: 你发送的是 POST请求,参数是: {},user-agent=requests spider

参数可以自己进行调整进行多次尝试。需要注意的就是带参数的 GET请求,GET请求的参数会自动拼接到 URL后面,我们直接访问拼接后的 URL和传递参数进行访问的到的响应都是一样的。虽然两种方式都能得到相同的响应,但还是强烈建议大家使用参数的方式来发起 GET请求。

2 处理响应

了解了怎么发起请求之后我们来看看怎么处理返回结果。在向服务器发起请求后我们会收到服务器返回的响应,响应包含了状态码、响应头、响应体等,这些在预备知识中讲过,没印象了的话可以回去再看一下。requests将这些都封装到了一个响应对象中(就是上面代码中的 r),通过这个响应对象我们可以很方便地获取这些值。

2.1 获取响应内容

通过 text和 content分别可以获取响应的文本内容和二进制内容,一般在我们请求网页时使用 text来获取响应内容,在下载文件或者图片这些二进制内容时使用 content来获取响应内容并保存。

2.2 获取状态码

通过 status_code可以获取服务器返回的状态码。我们可以根据状态码来确定请求是否成功,一般状态码为 200时表示请求成功,404时表示请求的页面不存在,500表示服务器错误等。详细的内容都列在下面的表格中:

状态码 解释
200 表示请求正常返回,一般情况下可以认为请求成功
301 请求重定向,服务器希望客户端访问其他的网址,一般在登录时会出现。
404 请求的网页在服务器上不存在
500 服务器内部错误,一般是请求过多或者是服务器在处理请求时出错
503 收到这个状态码说明被服务器禁止访问,大概率是爬虫被服务器识别出来了

2.3 获取网页编码

大部分时候我们通过 text获取网页文本内容时可以正常获取,但是还是有些网站会出现乱码的情况。这时可以使用 apparent_encoding来获取网页编码,并将 apparent_encoding赋值给 encoding,代码如下:

r = requests.get('http://www.geebos.cn/blog/test')
r.encoding = r.apparent_encoding
print(r.text)

2.4 获取 json数据

当返回的数据是 json格式时可以直接通过调用响应的 json方法来获取数据。json方法会返回数据序列化后的对象,一个字典或者列表。

r = requests.get('http://www.geebos.cn/blog/test?format=json')
print(r.json())

3 上传文件