大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语—​​不温不火​​​,本意是​​希望自己性情温和​​​。作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己所犯的错误希望能够帮助到很多和自己一样处于起步阶段的萌新。但由于水平有限,博客中难免会有一些错误出现,有纰漏之处恳请各位大佬不吝赐教!​



目录


零基础爬虫入门(三) | 抓取网页_json

前言

网络爬虫的一般过程零基础爬虫入门(三) | 抓取网页_chrome_02

一、了解URL

  • 统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简介的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器怎样处理它。

一个基本URL包含以下内容:

模式(或称协议)、服务器名称(或IP地址)、路径和文件名,如“协议://授权/路径?查询”。完整的、带有授权部分的统一资源标志符语法看上去如下:协议://用户名:密码@子域名。域名。顶级域名:端口号/目录/文件名.文件后缀?参数=值#标志。

eg:

零基础爬虫入门(三) | 抓取网页_大数据_03

二、常用的获取网页数据的方式

  • URLlib
  • URLlib.request
  • requests库(最常用)

2.1 URLlib

  • urllib是URL和lib两个单词共同构成的,URL就是网页的地址,lib是library(库)的缩写。
  • URL的一般格式为(带方括号[]的为可选项):​​protocol://hostname[port]/path/[; parameters][?query]#fragment​​。

在此我们先看一个小demo

# 百度首页
import urllib.request
response = urllib.request.urlopen("http://www.baidu.com")
html = response.read().decode("utf-8")
print(html)

零基础爬虫入门(三) | 抓取网页_python_04

2.2、urllib.request

  • urllib.request是Python标准库之一,是urllib库升级和python3.0后的合并结果,提取对YRL请求更加复杂的操作
  • urllib库除了提供urllib库的基本操作外,还提供了授权、重定向、cookies等其他HTTP高层接口操作。

官方文档(如有兴趣可以自行查看):

​https://docs.python.org/3/library/urllib.request.html​​​

零基础爬虫入门(三) | 抓取网页_json_05

1、urllib.request.urlopen

  • urlopen函数创建一个指定url或者被封装request的对象,以此为出发点获取数据流,并操作数据
  • urlopen的函数格式
urllib.request.urlopen(url,data = None,[timeout,]*,cafile = None, capath = None, cadefault = False,context = None)


timeout​:超时释放链接
cafile/capath/cadefault​:CA认证参数,用于HTTPS协议
context​:SSL链接选项,用于HTTPS


2、urllib.request.Request

  • 使用urllib.request库向httpbin.org发起请求,使用url和data向服务器发送get和post请求与urllib库一致。
  • urllib.request提供Request类,可用来定制请求:
urllib.request.Request(url,data = None,headers = {},origin_req_host = None,unverifiable = False,method = None)

代码详解:

零基础爬虫入门(三) | 抓取网页_chrome_06

  • 1. 代码
# coding=utf-8
from urllib import request
from urllib.parse import urlparse
url = "http://httpbin.org/post"
headers = {
"user-agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'
}
dict = {"name":"buwenbuhuo"}
data = bytes(urllib.parse.urlencode(dict),encoding = "utf8")
req = request.Request(url=url,data=data,headers=headers,method="POST")
response = request.urlopen(req)
print(response.read().decode("utf-8"))
  • 2. 运行结果
    零基础爬虫入门(三) | 抓取网页_大数据_07

3、urllib.request的高级特性

urllib.request几乎可以做到任何HTTP请求中所有的事情:


  • HTTPDefaultErrorHandler用于处理HTTP响应错误,错误都会抛出HTTPError类型的异常
  • HTTPRedirectHandler用于处理重定向
  • HTTPCookieProcessor用于处理Cookie
  • ProxyHandler用于设置代理,默认代理为空
  • HTTPPasswordMgr用于管理密码,它维护了用户名密码的表
  • HTTPBasicAuthHandler用于管理认证,如果一个链接打开时需要认证,那么用它来解决认证问题…


4、Opener

OpenerDirector:

  • OpenerDirector被称之为Opener,urllib.request.urlopen()这个方法,实际上它就是一个Opener
  • 为什么要引入Opener? 因为我们需要实现更高级的功能,之前我们使用的Request、urlopen()相当于类库为你封装好了及其常用的请求方法,利用它们两个我们就可以完成基本的请求,但是现在不一样了,我们需要实现更高级的功能,所以我们需要深入一层,使用更上层的实例来完成我们的操作。所以,在这里我们就用到了比调用urlopen()的对象更普通的对象,也就是Opener。

5、cookie

  • 网站使用Cookie保存用户的浏览信息,如会话ID,上次访问的状态等。
  • 客户端在请求的时候必须带上对应的Cookie,这样才能获取需要登录授权才能看到的内容

零基础爬虫入门(三) | 抓取网页_chrome_08

举例:获取百度Cookie

  • 1. 源码
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)
  • 2. 运行结果
    零基础爬虫入门(三) | 抓取网页_chrome_09
    获取到网站返回的cookie后,我们可能需要反复访问网站获取数据,这时需要发送携带cookie的请求。
    上述代码中的​​cookielib.CookieJar​​只能将Cookie保存在内存中,使用MozillaCookieJar可以将Cookie保存在文件中
  • 1. 源码
filename = 'cookie.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)
  • 2. 运行结果
    零基础爬虫入门(三) | 抓取网页_json_10

2.3、Requests库

Requests是用python语言基于urllib编写的,采用的是Apache2 Licensed开源协议的HTTP库。与urllib相比,Requests更加方便,可以节约我们大量的工作,建议爬虫使用Requests库。

官方文档链接:​​https://requests.readthedocs.io/en/master/​

1、Requests库安装

在终端中运行以下命令:​​pip install requests​

2、用requests发起请求

import requests
import json

# 用requests发起简单的GET请求
url_get = 'http://httpbin.org/get'
response = requests.get(url_get,timeout = 5)
print(json.loads(response.text)['args'])
# 用requests发起带参数的GET请求
kvs = {'k1':'v1','k2':'v2'}
response = requests.get(url_get,params=kvs,timeout = 5)
print(json.loads(response.text)['args'])
# 用requests 发起POST 请求
url_post = 'http://httpbin.org/post'
kvs = {'k1':'v1','k2':'v2'}
response = requests.post(url_post,data=kvs,timeout = 5)
print(response.json()['form'])

零基础爬虫入门(三) | 抓取网页_服务器_11

上图我们可以看出,方法名把发起的请求表达的很清晰,get就是GET,post就是POST。不仅如此,我们或得的​​response​​非常强大,可以直接得到很多信息,并且​​response​​中的内容不是一次性的,​​requests​​自动将响应的内容​​read​​出来,保存在​​text​​变量中,你想读取多少次就读多少次,我们看下​​response​​中都有哪些有用的信息:

print(response.url)
print(response.status_code)
print(response.headers)
print(response.cookies)
print(response.encoding) # requests会自动猜测响应内容的编码

import json
print(response.json() == json.loads(response.text)) # response.text 是响应内容,可以读取任意次,并且requests可以自动转换json

requests = response.request # 可以直接获取response对应的request
print(response.url)
print(response.headers) # 我们发起的request 是什么样子的一目了然

零基础爬虫入门(三) | 抓取网页_python_12

除了上面的信息,response 还提供了很多其它的信息。另外,除了 ​​get​​ 和 ​​post​​,​​requests​​ 还提供了显式的 ​​put​​、​​delete​​、​​head​​、​​options​​ 方法,分别对应相应的 HTTP 方法。感兴趣的读者可以深入探索一下。

3、Requests库发起POST请求

此部分截取自官方文档:

通常,如果你希望发送一些表单编码的数据-非常类似于HTML表单。为此,只需将字典传递给data参数即可。提出请求后,您的数据字典将自动进行表单编码:

>>> payload = {'key1': 'value1', 'key2': 'value2'}

>>> r = requests.post("https://httpbin.org/post", data=payload)
>>> print(r.text)
{
...
"form": {
"key2": "value2",
"key1": "value1"
},
...
}

该data参数还可以为每个键具有多个值。这可以通过创建data元组列表或以列表为值的字典来完成。当表单具有使用同一键的多个元素时,这特别有用:

import requests

>>> payload_tuples = [('key1', 'value1'), ('key1', 'value2')]
>>> r1 = requests.post('https://httpbin.org/post', data=payload_tuples)
>>> payload_dict = {'key1': ['value1', 'value2']}
>>> r2 = requests.post('https://httpbin.org/post', data=payload_dict)
>>> print(r1.text)
{
...
"form": {
"key1": [
"value1",
"value2"
]
},
...
}
>>> r1.text == r2.text
True

4、requests.Session

  • requests库的session对象能够帮我们跨请求保持某些参数,也会在同一个session实例发出的所有请求之间保持cookies
  • requests库的session对象还能为我们提供请求方法的缺省数据,通过设置session对象的属性来实现
import requests
# 创建一个session对象
s = requests.Session()
# 用session对象发出get请求,设置cookies
s.get('https://httpbin.org/cookies/set/sessioncookie/123456789')
# 用session对象发出另外一个get请求,获取cookies
r = s.get('https://httpbin.org/cookies')
# 显示结果
print(r.text)

零基础爬虫入门(三) | 抓取网页_服务器_13

​requests​​ 的大多数使用方法与 ​​urllib2​​ 类似。另外 ​​requests​​ 的文档很完善。这里主要讲解一下 ​​requests​​ 最强大,最常用的功能:会话保持。上面的代码中,我们连续发起的两次请求是没有关系的,这就会导致有些数据是无法获取的。如:

import requests
url_cookies = 'http://httpbin.org/cookies'
url_set_cookies = 'http://httpbin.org/cookies/set?k1=v1&k2=v2'
print(requests.get(url_cookies,timeout = 5).json())
print(requests.get(url_set_cookies,timeout = 5).json())
print(requests.get(url_cookies,timeout = 5).json())

零基础爬虫入门(三) | 抓取网页_大数据_14

可以看到,调用 ​​url_set_cookies​​ 设置 cookie 前后发起的 GET 请求得到的 cookie 都是空的。这就说明不同的请求之间是没有关系的。可能有人会对上面代码中的第5行的输出感到奇怪,因为上一篇文章我们用 urllib2 发起相同的请求时,得到的结果仍然是空的。这确实有一点奇怪,这是因为 ​​urllib2​​ 默认对所有请求都是忽略 cookie 的,哪怕是重定向的请求,而 ​​requests​​ 会在一个请求之内保存 cookie(url_set_cookies请求包含了一个重定向请求)。

下面的代码可以让多次请求保持在一个会话之内:

session = requests.Session()
print(requests.get(url_cookies,timeout = 5).json())
print(requests.get(url_set_cookies,timeout = 5).json())
print(requests.get(url_cookies,timeout = 5).json())

零基础爬虫入门(三) | 抓取网页_服务器_15

我们现在可以看到我们的第三次请求中包含了第二次请求设置的 cookie!是不是很简单。事实上,​​requests​​ 内部实现 cookie 的保持也利用了 ​​cookielib​​,感兴趣的同学可以深入探究一下。

requests库的特点:

  • 发起GET和POST请求,代码量小,简洁明快
  • 带持久Cookie的会话,自动管理Cookie
  • 优雅的key/value Cookie格式
  • 自动压缩
  • 自动内容解码

6、设置代理

import requests
url = 'http://httpbin.org/cookies/set?k1=v1&k2=v2'
proxies = {'http':'http://username:password@host:port','http://username:password@host:port'}
print(requests.get(url,proxies = proxies,timeout = 5).json()['args'])
# 上面的方法要给每个请求都要加上proxies参数,比较繁琐,可以为每个session设置一个默认的proxies
session = requests.Session()
session.proxies = proxies # 一个session中的所有请求都使用同一套代理
print(session.get(url,timeout = 5).json()['args'])

上面的代码当然是不能运行的,因为代理的格式是不正确的。等我们需要的时候,直接复用这段代码就可以了。 也许你会觉得前面对 urllib2 进行的大量练习都是徒劳的,因为 requests 非常简单易学!当然不是徒劳的,urllib2 是很基础的网络库,很多其它的网络库,包括requests,都是基于 urllib2 开发的。前面我们进行的练习会帮助我们更好地理解网络,理解 Python 对网络的处理,这对于我们以后开发可靠、高效的爬虫是大有裨益的。

需要注意的是:

​response​​中的内容是用​​unicode​​编码的,为了便于阅读我们需将其转换成中文,直接打印是不行的,因为​​Python​​将一个​​dict​​转换成字符串时保留了​​unicide​​编码,所以直接打印出来的不是中文。

这里我们采用另一种转换的方法:先将得到的​​form dict​​ 转换为 ​​unicode​​字符串(注意其中的​​ensure_ascii=False​​参数,它的含义是不对​​unicode​​字符转义),然后将得到的​​unicode​​字符串编码成​​UTF-8​​字符串,最后再转换成​​dict​​,方便输出。

三、浏览器的简单介绍

​Chrome​​中提供了检查网页元素的功能,叫做​​Chrome Inspect​​。在网页中通过点击右键可以查看该功能,如下图所示:

零基础爬虫入门(三) | 抓取网页_大数据_16

在本页调出​​Chrome Inspect​​,我们可以看到类似于下面的界面:

零基础爬虫入门(三) | 抓取网页_python_17

通常我们最常用的功能就是查看一个元素的源码,点击左上角的元素定位器,就可以选择网页中的不同元素,​​HTML​​源码区就会自动显示指定元素的源码,通常​​CSS​​显示区也会显示这个元素应用的样式。​​Chrome Inspect​​更加常用的功能是监控网络交互过程,选择功能栏中的​​Network​​,即可看到下面的界面:

零基础爬虫入门(三) | 抓取网页_chrome_18

​Chrome Network​​ 的交互区显示了一个网页加载过程,浏览器发起的所有请求。选择一个请求,右侧就会显示该请求的详情,包括请求头、响应头、响应内容等。​​Chrome Network​​是我们研究网页交互流程的重要工具。​​Cookie​​和​​Session​​是重要的网络技术,在​​Chrome Inspect​​中也可以查看网页​​Cookie​​,选择功能栏中的​​Application​​,即可看到下面的界面:

零基础爬虫入门(三) | 抓取网页_json_19

从​​Chrome Application​​的左侧选择​​Cookies​​,即可看到以​​K-V​​形式保存的​​Cookie​​。这个功能在我们研究网页的登录过程时非常有用。需要注意的是,在研究一个完整的网络交互过程前,要记得在​​Cookies​​上点击右键,然后点击​​Clear​​清空所有旧的​​Cookies​​。

​HTTP Response​​​的第一行,即​​Status Line​​ 中包含了状态码。状态码由三位数字组成,标志着服务器对客户端请求处理结果。状态码分为以下几类:


1xx :信息响应类,表示接收到请求并且继续处理
2xx :处理成功响应类,表示动作被成功接收、理解和响应
3xx :重定向响应类,为了完成指定的动作,必须进行进一步处理
4xx :客户端错误,客户端请求包含语法错误或者是不能被服务端理解
5xx :服务端错误,服务器不能正确执行一个有效的请求


下面是一些常见的状态码及其描述:


200 OK :请求已经被正确处理并响应。
301 Move Permanently :永久重定向。
302 Move Temporarily :临时重定向。
400 Bad Request :服务器不能理解请求。
401 Authentication Required :需要验证用户身份。
403 Forbidden :禁止访问资源。
404 Not Found :资源没有找到。
405 Method Not Allowed :在资源上使用了错误的方法,如应该用 POST,却用了 PUT。
408 Request Timeout :请求超时。
500 Internal Server Error :服务器内部错误。
501 Method Not Implemented :请求方法无效,如可能将 GET 写成 Get。
502 Bad Gateway :网关或者代理从上游服务器收到了错误的响应。
503 Service Unavailable :服务暂时不可用,可稍后尝试。
504 Gateway Timeout :网关或代理向上游服务器请求超时。


实际应用中,大多数网站都有反爬虫策略,响应状态码代表了服务器的处理结果,是我们调整爬虫抓取状态(如频率、ip)的重要参考。比如说我们一直正常运行的爬虫突然获取了403响应,这很可能是服务器识别了我们的爬虫,并拒绝了我们的请求。这时,我们就要减慢爬取频率,或者重启Session,甚至更换IP。

零基础爬虫入门(三) | 抓取网页_python_20

美好的日子总是短暂的,虽然还想继续与大家畅谈,但是本篇博文到此已经结束了,如果还嫌不够过瘾,不用担心,我们下篇见!

零基础爬虫入门(三) | 抓取网页_chrome_21


  好书不厌读百回,熟读课思子自知。而我想要成为全场最靓的仔,就必须坚持通过学习来获取更多知识,用知识改变命运,用博客见证成长,用行动证明我在努力。
  如果我的博客对你有帮助、如果你喜欢我的博客内容,请​​“点赞” “评论”“收藏”​​一键三连哦!听说点赞的人运气不会太差,每一天都会元气满满呦!如果实在要白嫖的话,那祝你开心每一天,欢迎常来我博客看看。
  码字不易,大家的支持就是我坚持下去的动力。点赞后不要忘了​​关注​​我哦!