静态网站是指全部由HTML代码格式页面组成的网站,所有的内容包含在网页文件中,通常没有后台数据库,页面不含程序并且无法交互。网页上也可以出现各种视觉动态效果,如GIF动画、FLASH动画、滚动字幕等,而网站主要是静态化的页面和代码组成,一般文件名均以htm、html、shtml等为后缀,静态网页一经发布到服务器上,无论是否被访问,都是一个独立存在的文件。早期的网站基本都是由静态网站构成的。本章将分别使用urllib3库、Requests库向链家二手房发送HTTP请求,并使用Chrome开发者工具、Xpath表达式、bs4解析、正则表达式解析获取的网页内容,最后将解析的结果分别保存到CSV文件和MySQL数据库中。
本章主要使用urllib3库和Requests库实现HTTP请求。
3.1.1使用urllib3库
urllib3 是一个强大的、用户友好的 Python HTTP 客户端。许多 Python 生态系统已经使用urllib3,其提供了Python 标准库中缺少的许多关键特性:
- 线程安全。
- 连接池。
- 客户端 TLS/SSL 验证。
- 使用多部分编码的文件上传。
- 重试请求和处理 HTTP 重定向的助手。
- 支持 gzip、deflate 和 brotli 编码。
- 对 HTTP 和 SOCKS 的代理支持。
- 100% 的测试覆盖率。
更多详细内容可以参考urllib3官方网址:https://urllib3.readthedocs.io/en/stable/index.html
使用urllib3库发送请求:
1.安装
urllib3可以使用pip安装,代码如下:
2.发送请求
首先,导入urllib3模块,代码如下:
其次,需要创建一个PoolManager实例来发出请求,该对象处理连接池和线程安全的所有细节,代码如下:
可以使用request()方法发送请求,代码如下:
- request()方法的基本语法如下:
- request(method, url, fields=None, headers=None, **urlopen_kw)
- 参数说明:
- method:接收str。表示发送请求的类型,与HTTP请求相同,如:GET、HEAD、POST等,无默认值,必须传入。
- url:接收str。表示发请求的网址,无默认值,必须传入。
- fields:接收dict。表示请求类型所带的参数。默认为None。
- headers:接收dict。表示请求头所带的参数。默认为None。
- **urlopen_kw:接收dict或其他python中的数据类型的数据。无默认值。
备注:由于响应内容过长,此处部分结果已省略。
不难发现响应内容就是使用浏览器访问该网页的网页源代码,可以通过Chrome查看网页源代码进行对比。
以上就是使用urllib3库对向静态网页发送请求获得响应的简单过程。除urllib3库以外还可以使用另外一个比较主流的三方库实现发送请求。
3.1.2使用requests库
Requests是一个原生的HTTP库, 可以发送原生的 HTTP/1.1 请求。不需要手动为 URL 添加查询字串,也不需要对POST数据进行表单编码。完全自动化的Keep-alive 和 HTTP 连接池的功能,完全满足如今Web的需求,具体特性如下:
- Keep-Alive & 连接池
- 国际化域名和 URL
- 带持久 cookie 的会话
- 浏览器式的 SSL 认证
- 自动内容解码
- 基本/摘要式的身份认证
- 优雅的 key/value cookie
- 自动解压
- Unicode 响应体
- HTTP(S) 代理支持
- 文件分块上传
- 流下载
- 连接超时
- 分块请求
- 支持 .netrc
更多详细内容可以参考Requests官方网址:https://docs.python-requests.org/en/latest/
使用Requests库发送请求:
1.安装
Requests库可以使用pip安装,代码如下:
2.发送请求
导入requests模块,代码如下:
使用requests库中的get()方法发送请求,代码如下:
除此以外还可以通过requests库request()方法发送请求,代码如下:
- request()方法的基本语法如下:
- requests.request(method, url, **kwargs)
- 参数说明:
- method:发送请求的方法:GET, OPTIONS, HEAD, POST, PUT, PATCH, 或DELETE。
- url:发送请求的网址。
- params:(可选)字典、元组、列表或字节列表,查询字符串,作为参数增加到url中,一般用于get请求,post请求也可以使用(不常用)。
- data:(可选)字典,元组列表,字节或文件对象,作为post请求的参数。
- json:(可选) JSON格式的数据,作为post请求的json参数。
- headers:(可选)字典类型, HTTP请求头信息。
- cookies: (可选)字典或cookieJar,响应头中的cookie。
- files:字典类型,传输文件,作为post请求文件流数据。
- auth:(可选)用于启用基本/摘要/自定义 HTTP 身份验证的身份验证元组。
- timeout: (可选) 设定超时时间,秒为单位,作为浮点数或(connect timeout, read timeout)元组。
- allow_redirects:(可选)布尔值。启用/禁用 GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD 重定向。默认为True。
- proxies:字典类型,设定访问代理服务器,可以增加登录认证。
- verify:布尔值。默认为True,认证SSL证书开关。
- stream:(可选)如果是False,则将立即下载响应内容。
- cert:(可选)如果是字符串,则为 ssl 客户端证书文件 (.pem) 的路径。如果是元组,则 (‘cert’, ‘key’) 对。
- 返回值:Response object。
示例:向https://www.httpbin.org/get发送请求
附加额外信息,例如想实现添加两个参数name和age,其中name是germey、age是25,于是url就可以写成如下内容:https://www.httpbin.org/get?name=germey&age=25。要构造这个请求链接,这样直接写是允许的,但是我们有更好的选择,一般情况下利用params参数就可以直接传递这种信息了,示例如下:
除了使用requests.request()方法外,还有一下六种方法可以使用,如表3-1所示:
以上这些方法可以使用requests.request()方法变换其中method参数实现,返回值都为响应对象(Response object)。其中**kwargs参数可以使用requests.request()方法中的其他参数,以关键字传参传入即可。一般情况下,使用get()方法向静态网页发请求。
向”https://ssr1.scrape.center/“发送请求,并查看返回的响应对象、结果类型、状态码、编码类型、响应头和获取到的网页内容,具体示例如代码3-2所示:
…
备注:由于响应内容过长,此处部分结果已省略。
由代码可知,可以使用response.status_code属性查看服务器返回的状态码,使用response.encoding属性可以查看网页编码类型,使用response.text属性可以查看响应内容的文本形式,使用response.content属性可以查看二进制的响应内容。
某些网站为了防止网页信息被恶意爬取,会设置反爬机制,通常情况下在发送请求时都需要构造请求头信息,也就是在get()方法中为参数headers传入请求头字段的某些信息,这些信息中”User-Agent”是一个比较重要的信息,可以在浏览器的Netword中任意选中一个数据包,“Headers”选项中的Requests Header中查找”User-Agent”字段的值,如图3-2所示:
发送请求获得响应后需要从响应内容中提取出有用的信息这个过程称为解析。通过解析网页可以获取网页源码中包含的有用信息,如文本、图片、链接、视频等。这就需要爬虫具备定位网页中信息的位置并提取网页内容的功能。这一节主要介绍三种解析网页信息的方法,同时还需要借助Chrome开发者工具查看网页结构和页面元素等信息。
3.2.1 使用Xpath表达式解析网页
XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。XPath基于XML的树状结构,使用路径表达式来选取 XML 文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。XPath 可用来在 XML 文档中对元素和属性进行遍历。XPath 含有超过 100 个内建的函数。这些函数用于字符串值、数值、日期和时间比较、节点和 QName 处理、序列处理、逻辑值等,几乎所有的定位的节点都可以用Xpath来选择。
1.Xpath节点
在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档节点(或称为根节点)。示例如下:
上面HTML文档中节点例子:
2.节点关系
- 父(Parent):除根节点以外,每个元素以及属性都有一个父。上例中head节点是title节点的父;
- 子(Children):元素节点可有零个、一个或多个子。上例中head节点、body节点是html节点的子;
- 同胞(Sibling):拥有相同的父的节点。上例中body节点中的p节点都是同胞,head节点和body节点也是同胞;
- 先辈(Ancestor):某节点的父、父的父。上例中p节点的先辈是body节点和html节点;
- 后代(Descendant):某个节点的子,子的子。上例中html节点的后代是head节点、title节点、body节点、p节点、a节点。
3.选取节点
XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。
常用的路径表达式,如表3-2所示:
4.谓语
谓语用来查找某个特定的节点或者包含某个指定的值的节点,谓语被嵌在路径后的方括号中,如表3-3所示:
5.功能函数
Xpath还提供了可以进行模糊搜索的功能函数,有时仅掌握了对象的部分特征,当需要模糊搜索该类对象时便可以使用功能函数来实现,如表3-4所示:
6.提取文本
使用text()方法可以提取某个子节点的直系文本,如果想要提取定位到的子节点及其子孙节点下的全部文本可以使用string方法来实现。
使用Xpath需要安装lxml,代码如下:
从lxml库中导入etree模块,代码如下:
需要使用HTML类对需要解析的响应对象进行初始化,HTML类的基本语法如下:
参数说明:
- text:接收str。需要转换的HTML字符串,无默认值。
- parser:接收str。解释器,无默认值。
- base_url:接收url。表示文档的原始URL,用于查找外部实体的相对路径。
爬取到的Scrape网页首页的相关信息,并使用etree.HTML()类初始化响应对象,为解析数据做好准备,如代码3-3所示:
爬虫通过解析网页获取到需要的数据后还需要将数据存储下来以便后期使用。可以将数据存储到文件中,也可以将数据存入数据库中,本小节主要介绍将使用Xpath表达式解析的数据保存到CSV文件中,将BeautifulSoup解析的数据通过PyMySQL保存到MySQL数据库中。
3.3.1 将数据存储到CSV文件
CSV逗号分隔值(Comma-Separated Values)有时也称为字符分隔值格式,是电子表格和数据库最常见的导入和导出格式。Python自带处理csv文件的库只需要导入就可以直接使用,无需安装。csv模块定义了读(reader)写(writer)函数,reader函数的基本语法如下:
参数说明:
- csvfile:文件路径、文件名称,如果 csvfile是文件对象,则打开它时应使用 newline=’’。
- dialect:用于不同的 CSV 变种的特定参数组
- fmtparams :可以覆写当前变种格式中的单个格式设置
返回值:返回reader对象
Reader 对象具有以下公开属性和方法,如表所示:
writer函数的基本语法如下:
参数同上
返回值:返回writer对象
Writer对象具有以下公开属性和方法,如表所示:
除此以外,csv模块还定义了DictReader类和DictWriter类处理映射关系内容的读写,DictWriter类的基本语法如下:
参数说明:
- f:需要写入的文件
- fieldnames:组成键的序列
- restval:如果字典缺少fieldnames中的键,则可选参数restval用于指定要写入的值
- extrasaction:默认值raise,传递给writerow() 方法的字典的某些键在fieldnames中找不到时则会引发ValueError,将其设置为 ignore,则字典中的其他键值将被忽略。
如代码3-8所示:
参数同上,示例如下:
将Xpath表达式解析得到的数据保存为csv文件,如代码3-9所示: