当前位置: 首页 > article >正文

python爬虫--实用又便捷的第三方模块--requests实战

我们学习了正则表达式和爬虫的相关基础知识,虽然有接触实战的案例,但是都是基础使用,今天我们来学习一下Python爬虫世界里的一些实用又便捷的第三方模块,今天的主要学习内容是网络
请求requests库和网页解析BeautifulSoup库。

网络请求 Requests

Python 提供了多个用来编写爬虫程序的库,有一个非常重要网络请求库就是 Requests 库,这个库的 宗旨是 HTTP 服务于人类

Requests Python 的第三方库,它的安装非常简便,如下所示:

pip install requests

Requests 库是在 urllib 的基础上开发而来,它使用 Python 语言编写,并且采用了 Apache2
Licensed(一种开源协议)的 HTTP 库。与 urllib 相比,Requests 更加方便、快捷,因此在编写爬虫程序 Requests 库使用较多,接下来跟着老师一起来学习requests库。

常用请求方法

requests.get()

该方法用于 GET 请求,表示向网站发起请求,获取页面响应对象。语法如下:

res = requests.get(url,headers=headers,params,timeout)

参数说明如下:

 url:要抓取的 url 地址。

 headers:用于包装请求头信息。

 params:请求时携带的查询字符串参数。

 timeout:超时时间,超过时间会抛出异常。

具体使用示例如下:

import requests

url = 'http://baidu.com'

response = requests.get(url)

print(response)

# print(response.text) 可以查看请求具体的返回数据信息

输出结果:

<Response [200]>

200 是请求返回状态码,表示请求成功。

如果我们想要请求时带上请求参数,使用也非常的简单,这里使用到了 http://httpbin.org,当我们请 http://httpbin.org/get 时会返回具体的请求信息, 示例如下所示:

import requests

data = {'name': '有霸夫', 'url': "www.ybf.com"}

response = requests.get('http://httpbin.org/get', params=data) # 直接拼接参数也可以

# response = requests.get('http://httpbin.org/get?name=ybf&age=33') # 调用响应对象

text属性,获取文本信息

print(response.text)

输出结果:

{

"args": {

"name": "\u6709\u9738\u592b", "url": "www.ybf.com"

},

"headers": { "Accept": "*/*",

"Accept-Encoding": "gzip, deflate", "Host": "httpbin.org",

"User-Agent": "python-requests/2.25.1",

"X-Amzn-Trace-Id": "Root=1-62216f84-2054fe065f625d4928c77cfa"
},

"origin": "175.0.53.160",

"url": "http://httpbin.org/get?name=\u6709\u9738\u592b&url=www.ybf.com"

}

requests.post()

该方法用于 POST 请求,先由用户向目标 url 提交数据,然后服务器返回一个 HttpResponse 响应对 象,语法如下:

response=requests.post(url,data={请求体的字典})

示例如下所示:

import requests

url = 'https://fanyi.baidu.com' # 百度翻译

# post请求体携带的参数,可通过开发者调试工具查看#查看步骤:NetWork选项->Headers选项->Form Data

data = {'from': 'zh', 'to': 'en', 'query': '欢迎参加跟有霸夫学编程课堂'}

response = requests.post(url, data=data) print(response)

# print(response.text) 可以查看请求具体的返回数据信息

输出结果:

<Response [200]>

chrome中查看 Form Data 的步骤非常的简单,如下图所示:

响应对象属性

当我们使用 Requests 模块向一个 URL 发起请求后会返回一个 HttpResponse 响应对象,该对象具有 以下常用属性:

常用属性

说明

encoding

查看或者指定响应字符编码

status_code

返回HTTP响应码

url

查看请求的 url 地址

headers

查看请求头信息

cookies

查看cookies 信息

text

以字符串形式输出

content

以字节流形式输出,若要保存下载图片需使用该属性。

使用示例如下所示:

import requests
response = requests.get('http://www.baidu.com')
print(response.encoding)
response.encoding = "utf-8" # 更改为utf-8编码
print(response.status_code) # 打印状态码
print(response.url) # 打印请求url
print(response.headers) # 打印头信息
print(response.cookies) # 打印cookie信息
print(response.text) # 以字符串形式打印网页源码
print(response.content) # 以字节流形式打印

输出结果:

#编码格式
ISO-8859-1
#响应码
200
#url地址
http://www.baidu.com/
#请求头信息
{'Cache-Control': 'private, no-cache, no-store, proxy-revalidate, no-transform',
'Connection': 'keep-alive', 'Content-Encoding': 'gzip', 'Content-Type':
'text/html', 'Date': 'Fri, 04 Mar 2022 02:04:36 GMT', 'Last-Modified': 'Mon, 23 Jan
2017 13:27:57 GMT', 'Pragma': 'no-cache', 'Server': 'bfe/1.0.8.18', 'Set-Cookie':
'BDORZ=27315; max-age=86400; domain=.baidu.com; path=/', 'Transfer-Encoding':
'chunked'}
#查看cookies信息
<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
...内容过长,此处省略后两项输出

在使用 requests请求网页时,我们可以很方便的拿到响应对象的各种信息,实际使用中可以很灵活的进行操作。

实用请求参数

SSL认证-verify参数

SSL 证书是数字证书的一种,类似于驾驶证、护照和营业执照。因为配置在服务器上,也称为 SSL 务器证书。SSL 证书遵守 SSL 协议,由受信任的数字证书颁发机构 CA(电子认证服务)颁发。 SSL 具有服 务器身份验证和数据传输加密功能。

verify 参数的作用是检查 SSL 证书认证,参数的默认值为 True,如果设置为 False 则表示不检查 SSL证书,此参数适用于没有经过 CA 机构认证的 HTTPS 类型的网站。其使用格式如下:

文本复制

response = requests.get( url=url, params=params, headers=headers, verify=False)

代理IP-proxies参数

一些网站为了限制爬虫从而设置了很多反爬策略,其中一项就是针对 IP 地址设置的。比如,访问网站超过规定次数导致流量异常,或者某个时间段内频繁地更换浏览器访问,存在上述行为的 IP 极有可能被网站封杀掉。
代理 IP 就是解决上述问题的,它突破了 IP 地址的访问限制,隐藏了本地网络的真实 IP,而使用第三方 IP 代替自己去访问网站。

1. 代理IP池

通过构建代理 IP 池可以让你编写的爬虫程序更加稳定,从 IP 池中随机选择一个 IP 去访问网站,而不使用固定的真实 IP。总之将爬虫程序伪装的越像人,它就越不容易被网站封杀。当然代理 IP 也不是完全不能被察觉,通过端口探测技等术识仍然可以辨别。其实爬虫与反爬虫永远相互斗争的,就看谁的技术更加厉害。

2. proxies参数

Requests 提供了一个代理 IP 参数 proxies ,该参数的语法结构如下:

proxies = {
'协议类型(http/https)':'协议类型://IP地址:端口号'
}

下面构建了两个协议版本的代理 IP,示例如下:

proxies = {
'http':'http://IP:端口号',
'https':'https://IP:端口号'
}

3. 代理IP使用

下面通过简单演示如何使用 proxies 参数,示例如下:

import requests
url = 'http://httpbin.org/get'
headers = {'User-Agent': 'Mozilla/5.0'}
proxies = {'http': 'http://1.194.238.242:3828'} #网上找的免费代理 ip
html = requests.get(url, proxies=proxies, headers=headers, timeout=10).text
print(html)

输出结果:

 {
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Cache-Control": "max-age=259200",
"Host": "httpbin.org",
"User-Agent": "Mozilla/5.0",
"X-Amzn-Trace-Id": "Root=1-622b1032-3ef292bc349cd9ca3d57e39f"
},
# 此时显示就是代理ip了
"origin": "1.194.238.242",
"url": "http://httpbin.org/get"
}

由于上述示例使用的是免费代理 IP,因此其质量、稳定性较差,可能会随时失效。如果想构建一个稳 定的代理 IP 池,就需要花费成本。

4.付费代理IP

网上有许多提供代理 IP 服务的网站,比如快代理、携趣代理等。这些网站也提供了相关文档说明,以 API 接口,爬虫程序通过访问 API 接口,就可以构建自己的代理 IP 池。

付费代理 IP 按照资源类型可划分为:开发代理、私密代理、隧道代理、独享代理,其中最常使用的是 开放代理与私密代理。

开放代理:开放代理是从公网收集的代理服务器,具有 IP 数量大,使用成本低的特点,全年超过 80% 的时间都能有 3000 个以上的代理 IP 可供提取使用。

私密代理:私密代理是基于云主机构建的高品质代理服务器,为您提供高速、可信赖的网络代理服 务。私密代理每天可用 IP 数量超过 20 万个,可用率在 95 %以上,1 次可提取 IP 数量超过 700 个,可以 为爬虫业务提供强大的助力。

付费代理的收费标准根据 IP 使用的时间长短,以及 IP 的质量高低,从几元到几百元不等,网上有很 多提供免费代理 IP 的网站,不过想找到一个质量较高的免费代理好比大海捞针。

用户认证-auth参数

Requests 提供了一个 auth 参数,该参数的支持用户认证功能,也就是适合那些需要验证用户名、密码的网站。auth 的参数形式是一个元组,其格式如下:

auth = ('username','password')

其使用示例如下所示:

import requests # 导入requests模块

# 定义请求地址

url = 'http://sck.rjkflm.com:666/spider/auth/' ah = ('admin', 'admin')

response = requests.get(url=url, auth=ah)

if response.status   code == 200: print(response.text)

Requests 库实战应用

接下来我们学习使用 Requsets 库下载图片。
首先打开天堂图片网(https://www.ivsky.com/),然后使用 Chrome 开发者工具随意查看一张图片
的源地址,如下图所示:

<img src="//img.ivsky.com/img/tupian/slides/202109/09/xiniu-001.jpg">

可以将上述 url 粘贴至浏览器地址栏进行验证。当我们确定图片地址后,就可以使用 requests 库进行 编码了:

import requests
url = 'https://img.ivsky.com/img/tupian/slides/202109/09/xiniu-001.jpg'
headers = {'User-Agent':'Mozilla/4.0'}
html = requests.get(url=url, headers=headers).content # 读取图片需要使用content属性
with open('D:/requests_img.jpg', 'wb') as f: # 以二进制的方式下载图片
        f.write(html)

最后,在D盘目录下可以找到已经下载好的图片。

网页解析 BeautifulSoup 库

BeautifulSoup 简称 BS4(其中 4 表示版本号)是一个 Python 第三方库,它可以从 HTML 或 XML 文档中快速地提取指定的数据。Beautiful Soup 语法简单,使用方便,并且容易理解,同学们可以跟着霸夫老师快速地学习并掌握它。

下面我们讲解 BS4 的基本语法。
由于 BautifulSoup 是第三方库,因此需要单独下载,下载方式非常简单,执行以下命令即可安装

pip install bs4

由于 BS4 解析页面时需要依赖文档解析器,所以还需要安装 lxml 作为解析库:

pip install lxml

Python 也自带了一个文档解析库 html.parser 但是其解析速度要稍慢于 lxml。除了上述解析器外, 还可以使用 html5lib 解析器,安装方式如下:

pip install html5lib

该解析器生成 HTML 格式的文档,但速度较慢。

BS4解析对象

创建 BS4 解析对象是万事开头的第一步,这非常地简单,语法格式如下所示:

#导入解析包
from bs4 import BeautifulSoup
#创建beautifulsoup解析对象
soup = BeautifulSoup(html_doc, 'html.parser')

上述代码中,html_doc 表示要解析的文档,而 html.parser 表示解析文档时所用的解析器,此处的解 析器也可以是 'lxml' 或者 'html5lib',示例代码如下所示:

# -*- coding: UTF-8 -*-
from bs4 import BeautifulSoup
html_doc = """<html><head><title>"跟有霸夫学编程"</title></head><body><p
class="title"><b>www.youbafu.com</b></p><p class="website">跟有霸夫学编程<a
href="http://youbafu.com/python/" id="link1">python教程</a><a
href="http://youbafu.com/c/" id="link2">c语言教程</a>"""
soup = BeautifulSoup(html_doc, 'html.parser') # prettify()用于格式化输出html/xml文档
print(soup.prettify())

输出结果:

<html>
    <head>
        <title>
            "跟有霸夫学编程"
        </title>
    </head>
<body>
    <p class="title">
        <b>
            www.youbafu.com
        </b>
    </p>
    <p class="website">
        跟有霸夫学编程
        <a href="http://youbafu.com/python/" id="link1">
            python教程
        </a>
        <a href="http://youbafu.com/c/" id="link2">
            c语言教程
        </a>
    </p>

</html>

如果是外部文档,您也可以通过 open() 的方式打开读取,语法格式如下:

soup = BeautifulSoup(open('html_doc.html', encoding='utf8'), 'lxml')

BS4常用语法

接下来一起学习一下爬虫中经常用到的 BS4 解析方法。
Beautiful Soup 将 HTML 文档转换成一个树形结构,该结构有利于快速地遍历和搜索 HTML 文档。下
面使用树状结构来描述一段 HTML 文档:

<html>
<head><title>跟有霸夫学编程</title></head>
<body>
<h1>www.youbafu.com</h1>
<p><b>一个学习编程的网站</b></p>
</body>
</html>

树状图如下所示:

文档树中的每个节点都是 Python 对象,这些对象大致分为四类:Tag , NavigableString , BeautifulSoup , Comment 。其中使用最多的是 Tag NavigableString

 Tag:标签类,HTML 文档中所有的标签都可以看做 Tag 对象。

 NavigableString:字符串类,指的是标签中的文本内容,使用 textstringstrings 来获取文本 内容。

 BeautifulSoup:表示一个 HTML 文档的全部内容,您可以把它当作一个人特殊的 Tag 对象。

 Comment:表示 HTML 文档中的注释内容以及特殊字符串,它是一个特殊的 NavigableString

Tag节点

标签(Tag)是组成 HTML 文档的基本元素。在 BS4 中,通过标签名和标签属性可以提取出想要的内 容。看一组简单的示例:

from bs4 import BeautifulSoup
soup = BeautifulSoup('<p class="Web site url"><b>www.youbafu.com</b></p>',
'html.parser') # 获取整个p标签的html代码
print(soup.p) # 获取p标签
print(soup.p.b) # 获取b标签
print(soup.p.text) # 获取p标签内容,使用NavigableString类中的string、text、get_text()
print(soup.p.attrs) # 返回一个字典,里面是多有属性和值
print(type(soup.p)) # 查看返回的数据类型
print(soup.p['class']) # 根据属性,获取标签的属性值,返回值为列表
soup.p['class'] = ['Web', 'Site'] # 给class属性赋值,此时属性值由列表转换为字符串
print(soup.p)

输出结果如下:

soup.p输出结果:
<p class="Web site url"><b>www.youbafu.com</b></p>
soup.p.b输出结果:
<b>www.youbafu.com</b>
soup.p.text输出结果:
www.youbafu.com
soup.p.attrs输出结果:
{'class': ['Web', 'site', 'url']}
type(soup.p)输出结果:
<class 'bs4.element.Tag'>
soup.p['class']输出结果:
['Web', 'site', 'url']
class属性重新赋值:
<p class="Web site url"><b>www.youbafu.com</b></p>

遍历节点

Tag 对象提供了许多遍历 tag 节点的属性,比如 contents、children 用来遍历子节点;parent 与
parents 用来遍历父节点;而 next_sibling 与 previous_sibling 则用来遍历兄弟节点 。示例如下:

html_doc = """<html><head><title>"跟有霸夫学编程"</title></head><body><p
class="title"><b>www.youbafu.com</b></p><p class="website">一个学习编程的网站</p><a href="http://www.youbafu.com/python/" id="link1">python教程</a>
<a href="http://www.youbafu.com/c/" id="link2">c语言教程</a> </body></html>"""
soup = BeautifulSoup(html_doc, 'html.parser')
body_tag = soup.body
print(body_tag)
print(body_tag.contents) # 以列表的形式输出,所有子节点

输出结果:

<body><p class="title"><b>www.youbafu.com</b></p><p class="website">一个学习编程的网站
</p><a href="http://www.youbafu.com/python/" id="link1">python教程</a>
<a href="http://www.youbafu.com/c/" id="link2">c语言教程</a> </body>


#以列表的形式输出
[<p class="title"><b>www.youbafu.com</b></p>, <p class="website">一个学习编程的网站
</p>, <a href="http://www.youbafu.com/python/" id="link1">python教程</a>, '\n', <a
href="http://www.youbafu.com/c/" id="link2">c语言教程</a>, ' ']

Tag children 属性会生成一个可迭代对象,可以用来遍历子节点,示例如下:

for child in body_tag.children:
print(child)

输出结果:

<p class="title"><b>www.youbafu.com</b></p>
<p class="website">一个学习编程的网站</p>
<a href="http://www.youbafu.com/python/" id="link1">python教程</a>
<a href="http://www.youbafu.com/c/" id="link2">c语言教程</a>

find_all() 与 find()

find_all() 与 find() 是解析 HTML 文档的常用方法,它们可以在 HTML 文档中按照一定的条件(相当于过滤器)查找所需内容。find() 与 find_all() 的语法格式相似,希望大家在学习的时候,可以举一反三。
BS4 库中定义了许多用于搜索的方法,find() 与 find_all() 是最为关键的两个方法,其余方法的参数和使用与其类似。

find_all()

find_all() 方法用来搜索当前 tag 的所有子节点,并判断这些节点是否符合过滤条件,最后以列表形式将符合条件的内容返回,语法格式如下:

find_all( name , attrs , recursive , text , limit )

参数说明:

 name查找所有名字为 name tag 标签,字符串对象会被自动忽略。

 attrs按照属性名和属性值搜索 tag 标签,注意由于 class Python 的关键字吗,所以要使用
"class_"

 recursivefind_all() 会搜索 tag 的所有子孙节点,设置 recursive=False 可以只搜索 tag 的直接 子节点。

 text用来搜文档中的字符串内容,该参数可以接受字符串 、正则表达式 、列表、True

 limit由于 find_all() 会返回所有的搜索结果,这样会影响执行效率,通过 limit 参数可以限制返 回结果的数量。

find_all() 使用示例如下:

from bs4 import BeautifulSoup
html_doc = """<html><head><title>"跟有霸夫学编程"</title></head><body><p
class="title"><b>www.youbafu.com</b></p><p class="website">一个学习编程的网站</p><a href="http://www.youbafu.com/python/" id="link1">python教程</a><a href="http://www.youbafu.com/c/" id="link2">c语言教程</a><a href="http://www.youbafu.com/django/" id="link3">django教程</a><p class="vip">加入我
们阅读所有教程</p><a href="http://www.youbafu.com/vip" id="link4">成为vip</a>"""


# 创建soup解析对象
soup = BeautifulSoup(html_doc, 'html.parser')
print(soup.find_all("a")) # 查找所有a标签并返回
print(soup.find_all("a", limit=2)) # 查找前两条a标签并返回

'html.parser' 是 Python 的 BeautifulSoup 库中的一个解析器选项。它指定了用来解析 HTML 文档的具体解析器。html.parser 是 Python 标准库中自带的一个 HTML 解析器,它具有以下特点:

  1. 内置解析器html.parser 是 Python 标准库的一部分,无需额外安装。它的功能适用于大多数常见的 HTML 解析需求。

  2. 效率适中:它提供了一个平衡的性能和灵活性,不像一些外部解析器(如 lxml)那样快,但也比一些其他解析器更易于使用。

  3. 支持 HTML5html.parser 支持 HTML5 的大部分语法和特性,使其能够处理现代的 HTML 文档。

最后以列表的形式返回输出结果,如下所示:

[<a href="http://www.youbafu.com/python/" id="link1">python教程</a>, <a
href="http://www.youbafu.com/c/" id="link2">c语言教程</a>, <a
href="http://www.youbafu.com/django/" id="link3">django教程</a>, <a
href="http://www.youbafu.com/vip" id="link4">成为vip</a>]
[<a href="http://www.youbafu.com/python/" id="link1">python教程</a>, <a
href="http://www.youbafu.com/c/" id="link2">c语言教程</a>]

按照标签属性以及属性值查找 HTML 文档,如下所示

print(soup.find_all("p", class_="website"))
print(soup.find_all(id="link4"))

输出结果:

[<p class="website">一个学习编程的网站</p>]
[<a href="http://www.youbafu.com/vip" id="link4">成为vip</a>]

正则表达式、列表,以及 True 也可以当做过滤条件,使用示例如下:

# 查找tag标签
print(soup.find_all(['b', 'a']))


# 正则表达式匹配id属性值
print(soup.find_all('a', id=re.compile(r'.\d')))

print(soup.find_all(id=True)) # True可以匹配任何值,下面代码会查找所有tag,并返回相应的tag名称

for tag in soup.find_all(True):
        print(tag.name, end=" ")

# 输出所有以b开始的tag标签
for tag in soup.find_all(re.compile("^b")):
        print(tag.name)

输出结果如下:

第一个print输出:
[<b>www.youbafu.com</b>, <a href="http://www.youbafu.com/python/" id="link1">python
教程</a>, <a href="http://www.youbafu.com/c/" id="link2">c语言教程</a>, <a
href="http://www.youbafu.com/django/" id="link3">django教程</a>, <a
href="http://www.youbafu.com/vip" id="link4">成为vip</a>]
第二个print输出:
[<a href="http://www.youbafu.com/python/" id="link1">python教程</a>, <a
href="http://www.youbafu.com/c/" id="link2">c语言教程</a>, <a
href="http://www.youbafu.com/django/" id="link3">django教程</a>, <a
href="http://www.youbafu.com/vip" id="link4">成为vip</a>]
第三个print输出:
[<a href="http://www.youbafu.com/python/" id="link1">python教程</a>, <a
href="http://www.youbafu.com/c/" id="link2">c语言教程</a>, <a
href="http://www.youbafu.com/django/" id="link3">django教程</a>, <a
href="http://www.youbafu.com/vip" id="link4">成为vip</a>]
第四个print输出:
html head title body p b p a a a p a
最后一个输出:
body b

BS4 为了简化代码,为 find_all() 提供了一种简化写法,如下所示:

#简化前
soup.find_all("a")
#简化后
soup("a")

上述两种的方法的输出结果是相同的。

find()

find() 方法与 find_all() 类似,不同之处在于 find_all() 会将文档中所有符合条件的结果返回,而 find() 仅返回一个符合条件的结果,所以 find() 方法没有 limit 参数。使用示例如下:

from bs4 import BeautifulSoup
import re
html_doc = """<html><head><title>"跟拉拉学编程"</title></head><body><p
class="title"><b>www.youbafu.com</b></p><p class="website">一个学习编程的网站</p><a
href="http://www.youbafu.com/python/" id="link1">python教程</a><a
href="http://www.youbafu.com/c/" id="link2">c语言教程</a><a
href="http://www.youbafu.com/django/" id="link3">django教程</a><p class="vip">加入我
们阅读所有教程</p><a href="http://www.youbafu.com/vip" id="link4">成为vip</a>"""
# 创建soup解析对象
soup = BeautifulSoup(html_doc, 'html.parser')
# 查找第一个a并直接返回结果
print(soup.find('a'))
# 查找title
print(soup.find('title'))
# 匹配指定href属性的a标签
print(soup.find('a', href='http://www.youbafu.com/python/'))
# 根据属性值正则匹配
print(soup.find(class_=re.compile('tit')))
# attrs参数值
print(soup.find(attrs={'class': 'vip'}))

输出结果如下:

<a href="http://www.youbafu.com/python/" id="link1">python教程</a>
<title>"跟拉拉学编程"</title>
<a href="http://www.youbafu.com/python/" id="link1">python教程</a>
<p class="title"><b>www.youbafu.com</b></p>
<p class="vip">加入我们阅读所有教程</p>

使用 find() 时,如果没有找到查询标签会返回 None,而 find_all() 方法返回空列表。示例如下:

print(soup.find('bdi'))
print(soup.find_all('audio'))

输出结果如下:

None
[]

BS4 也为 find()提供了简化写法,如下所示:

#简化写法
print(soup.head.title)
#上面代码等价于
print(soup.find("head").find("title"))

两种写法的输出结果相同,如下所示:

<title>"跟有霸夫学编程"</title>
<title>"跟有霸夫学编程"</title>

css选择器

BS4 支持大部分的 CSS 选择器,比如常见的标签选择器、类选择器、id 选择器,以及层级选择器。Beautiful Soup 提供了一个 select() 方法,通过向该方法中添加选择器,就可以在 HTML 文档中搜索到与之对应的内容。应用示例如下:

from bs4 import BeautifulSoup
html_doc = """<html><head><title>"跟拉拉学编程"</title></head>
<body><p class="title"><b>www.youbafu.com</b></p><p class="website">一个学习编程的网站
</p>
<a href="http://www.youbafu.com/python/" id="link1">python教程</a>
<a href="http://www.youbafu.com/c/" id="link2">c语言教程</a>
<a href="http://www.youbafu.com/django/" id="link3">django教程</a>
<p class="vip">加入我们阅读所有教程</p>
<a href="http://www.youbafu.com/vip" id="link4">成为vip</a>
<p class="introduce">介绍:<a href="http://www.youbafu.com/about.html" id="link5">关
于网站</a>
<a href="http://www.youbafu.com/about0.html" id="link6">关于站长</a></p>"""
soup = BeautifulSoup(html_doc, 'html.parser')
# 根据元素标签查找
print(soup.select('title'))


# 根据属性选择器查找
print(soup.select('a[href]'))


# 根据类查找
print(soup.select('.vip'))


# 后代节点查找
print(soup.select('html head title'))


# 查找兄弟节点
print(soup.select('p + a'))


# 根据id选择p标签的兄弟节点
print(soup.select('p ~ #link3'))


# nth-of-type(n)选择器,用于匹配同类型中的第n个同级兄弟元素
print(soup.select('p ~ a:nth-of-type(1)'))


# 查找子节点
print(soup.select('p > a'))
print(soup.select('.introduce > #link5'))

输出结果:

一个输出:
[<title>"跟拉拉学编程"</title>]

二个输出:

[<a href="http://www.youbafu.com/python/" id="link1">python教程</a>, <a href="http://www.youbafu.com/c/" id="link2">c语言教程</a>, <a
href="http://www.youbafu.com/django/" id="link3">django教程</a>, <a
href="http://www.youbafu.com/vip" id="link4">成为vip</a>, <a
href="http://www.youbafu.com/about.html" id="link5">关于网站</a>, <a
href="http://www.youbafu.com/about0.html" id="link6">关于站长</a>]

第三个输出:

[<p class="vip">加入我们阅读所有教程</p>]


第四个输出:

[<title>"跟有霸夫学编程"</title>]


第五个输出:

[<a href="http://www.youbafu.com/python/" id="link1">python教程</a>, <a
href="http://www.youbafu.com/vip" id="link4">成为vip</a>]


第六个输出:

[<a href="http://www.youbafu.com/django/" id="link3">django教程</a>]

第七个输出:

[<a href="http://www.youbafu.com/python/" id="link1">python教程</a>]

第八个输出:

[<a href="http://www.youbafu.com/about.html" id="link5">关于网站</a>, <ahref="http://www.youbafu.com/about0.html" id="link6">关于站长</a>]

最后的print输出:

[<a href="http://www.youbafu.com/about.html" id="link5">关于网站</a>]

BS4 实战应用

上节课学习使用正则表达式爬取豆瓣电影top250同学们还记得吗?今天还是继续以豆瓣电影top250为例,使用BS4来进行演示,并结合面向对象的方式来编码,并将结果存储到Excel表格中。
再一起来回顾一下豆瓣电影的元素结构:

<li>
        <div class="item">
                <div class="pic">
                        <em class="">1</em>
                        <a href="https://movie.douban.com/subject/1292052/">
                                <img width="100" alt="肖申克的救赎" src="https://img2.doubanio.com/view/photo/s_ratio_poster/public/p480747492.webp" class="">
                        </a>
                </div>
        <div class="info">
            <div class="hd">
                <a href="https://movie.douban.com/subject/1292052/" class="">
                    <span class="title">肖申克的救赎</span>
                    <span class="title">&nbsp;/&nbsp;The Shawshank Redemption</span>
                    <span class="other">&nbsp;/&nbsp;月黑高飞(港) / 刺激1995(台</span>
                </a>
                <span class="playable">[可播放]</span>
            </div>
            <div class="bd">
                <p class="">
                    导演: 弗兰克·德拉邦特 Frank Darabont&nbsp;&nbsp;&nbsp;主演: 蒂姆·罗宾斯 Tim Robbins /...<br>
                    1994&nbsp;/&nbsp;美国&nbsp;/&nbsp;犯罪 剧情
                </p>
                <div class="star">
                    <span class="rating5-t"></span>
                    <span class="rating_num" property="v:average">9.7</span>
                    <span property="v:best" content="10.0"></span>
                    <span>2564578人评价</span>
                </div>
                <p class="quote">
                    <span class="inq">希望让人自由。</span>
                </p>
            </div>
        </div>
    </div>
</li>

核心的解析代码为:

    def parse(self, text):
        soup = BeautifulSoup(text, 'lxml')
        movie_list = soup.find_all('div', class_='item')
        for movie in movie_list:
            movie_info = {'title': movie.find('span', class_='title').text,
                          'score': movie.find('span', class_='rating_num').text}

            d_info = movie.find('div', class_='bd').p.text.replace(u'\xa0', '
').replace(u'\u3000', ' ').split("\n")
            movie_info['artists'] = d_info[1].strip()
            mi = d_info[2].strip()
            movie_info['time'] = mi.split('/')[0].strip()
            movie_info['region'] = mi.split('/')[1].strip()
            movie_info['category'] = mi.split('/')[2].strip()

            quote = movie.find('span', class_='inq')
            movie_info['quote'] = quote.text if quote else None
            star = movie.find('div', class_='star')
            movie_info['comment_num'] = star.find_all('span')[-1].text[:-3]
            self.movies.append(movie_info)

        next_page = soup.find('span', class_='next').a
        if next_page:
            next_url = self.baseurl + next_page['href']
            text = self.start_requests(next_url)

            self.parse(text)

完整代码:

import requests # 导入网页请求库
from bs4 import BeautifulSoup # 导入网页解析库
import pandas
import json
import csv

class DoubanTopMovies(object):
    headers = {
        'Host': 'movie.douban.com',
        'Origin': 'movie.douban.com',
        'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Mobile Safari/537.36',
    }
    json_file = r'data/bs4_movies.json'

    def __init__(self):
        self.baseurl = 'https://movie.douban.com/top250'
        self.movies = []

    def start_requests(self, url):
        r = requests.get(url, headers=self.headers)
        return r.content

    def parse(self, text):
        soup = BeautifulSoup(text, 'lxml')
        movie_list = soup.find_all('div', class_='item')
        for movie in movie_list:
            movie_info = {'title': movie.find('span', class_='title').text,
                          'score': movie.find('span', class_='rating_num').text}

            d_info = movie.find('div', class_='bd').p.text.replace(u'\xa0', ' ').replace(u'\u3000', ' ').split("\n")
            movie_info['artists'] = d_info[1].strip()
            mi = d_info[2].strip()
            movie_info['time'] = mi.split('/')[0].strip()
            movie_info['region'] = mi.split('/')[1].strip()
            movie_info['category'] = mi.split('/')[2].strip()
            quote = movie.find('span', class_='inq')
            movie_info['quote'] = quote.text if quote else None
            star = movie.find('div', class_='star')
            movie_info['comment_num'] = star.find_all('span')[-1].text[:-3]
            self.movies.append(movie_info)

        next_page = soup.find('span', class_='next').a
        if next_page:
            next_url = self.baseurl + next_page['href']
            text = self.start_requests(next_url)
            self.parse(text)

    def write_json(self, result):
        s = json.dumps(result, indent=4, ensure_ascii=False)
        with open(self.json_file, 'w', encoding='utf-8') as f:
            f.write(s)

    def write_cvs(self, data):
        with open(r'data/bs4_movies.csv', 'w', encoding='utf-8') as f:
            w = csv.DictWriter(f, fieldnames=data[0].keys())
            w.writeheader()
            w.writerows(data)

    def write_excel(self, data):
        pdfile = pandas.DataFrame(data)
        pdfile.to_excel(r'data/bs4_movies.xlsx', sheet_name="豆瓣电影")
    
    def start(self):
        text = self.start_requests(self.baseurl)
        self.parse(text)
        # self.write_json(self.movies)
        # self.write_cvs(self.movies)
        self.write_excel(self.movies)
    
if __name__ == '__main__':
    douban = DoubanTopMovies()
    douban.start()

课程总结

        本节课是爬虫课程的第三节课,我们在学习了正则表达式和爬虫基础知识后,开始学习Python爬虫的第三方优秀库,本节课主要学习了网络请求 requests 库,和网页解析库 BeautifulSoup 库(BS4),这些库在封装了很多基础的方法,使用方便快捷,功能强大,熟练掌握了这些库,在以后编写爬虫时会有事半功倍的效果。

课后练习

编程题
        Requests 库实战应用介绍了如何下载单张图片,根据代码实现可下载指定网络图片的函数
download(img_url),img_url为网络图片地址,并爬取豆瓣电影top250(https://movie.douban.com/top250)第一页的所有图片,利用该函数保存到D:\images目录下。
        参考思路:首先通过requests库请求网页内容,利用BeautifulSoup解析网页内容,然后查找所有img标签,再提取img标签中的图片链接,调用通过request库请求图片链接并保存到指定目录下。

要完成这个任务,你需要编写两个主要功能:

1. **下载图片的函数** `download(img_url)`:该函数接受一个图片的 URL,并将图片保存到本地指定目录下。
2. **爬取豆瓣电影 Top 250 第一页的图片**:这个过程涉及到请求网页内容,解析网页中的图片链接,并使用上面的 `download` 函数下载这些图片。

下面是完整的代码示例:

```python
import requests
from bs4 import BeautifulSoup
import os

def download(img_url, save_path):
    """
    下载图片并保存到指定路径
    :param img_url: 图片的 URL
    :param save_path: 图片保存的路径
    """
    try:
        # 发送请求获取图片内容
        response = requests.get(img_url, stream=True)
        response.raise_for_status()  # 检查请求是否成功
        
        # 打开文件并写入图片内容
        with open(save_path, 'wb') as file:
            for chunk in response.iter_content(chunk_size=8192):
                file.write(chunk)
        print(f"Image saved to {save_path}")
    except Exception as e:
        print(f"An error occurred: {e}")

def fetch_douban_images(base_url, save_dir):
    """
    爬取豆瓣电影 Top 250 第一页的所有图片
    :param base_url: 豆瓣电影 Top 250 的 URL
    :param save_dir: 图片保存的目录
    """
    try:
        # 发送请求获取网页内容
        response = requests.get(base_url)
        response.raise_for_status()
        
        # 解析网页内容
        soup = BeautifulSoup(response.text, 'html.parser')
        
        # 查找所有图片标签
        img_tags = soup.find_all('img')
        
        # 遍历图片标签
        for img in img_tags:
            img_url = img.get('src')
            if img_url:
                # 构建图片文件名
                img_name = img_url.split('/')[-1]
                img_path = os.path.join(save_dir, img_name)
                
                # 下载图片
                download(img_url, img_path)
                
    except Exception as e:
        print(f"An error occurred: {e}")

# 设置豆瓣电影 Top 250 第一页的 URL
base_url = 'https://movie.douban.com/top250'
# 设置图片保存的目录
save_dir = 'D:/images'

# 创建保存目录(如果不存在的话)
os.makedirs(save_dir, exist_ok=True)

# 执行爬取并下载图片
fetch_douban_images(base_url, save_dir)
```

### 说明:

1. **`download(img_url, save_path)`**:
   - 发送 HTTP 请求获取图片内容。
   - 使用 `stream=True` 来处理大文件。
   - 将图片内容写入指定路径的文件中。

2. **`fetch_douban_images(base_url, save_dir)`**:
   - 发送 HTTP 请求获取豆瓣电影 Top 250 页面内容。
   - 使用 BeautifulSoup 解析 HTML。
   - 查找所有 `img` 标签并提取 `src` 属性值。
   - 对每个图片链接,使用 `download` 函数下载图片并保存到指定目录中。

3. **主程序部分**:
   - 设置豆瓣电影的 URL 和保存图片的目录。
   - 创建目录(如果不存在的话)。
   - 调用 `fetch_douban_images` 函数来下载图片。

这样,你就可以将豆瓣电影 Top 250 第一页的所有图片下载到本地指定目录下。

http://www.kler.cn/news/303333.html

相关文章:

  • 架构师知识梳理(七):软件工程-测试
  • 【智路】智路OS Perception Pipeline
  • 文件批量添加水印和密码合并单元格完整版
  • Python基础语法(2)
  • 【运维监控】Prometheus+grafana监控spring boot 3运行情况
  • 实现快速产出的短视频剪辑工具
  • Object.entries()
  • 力扣之1783.大满贯数量
  • zabbix之钉钉告警
  • SpringMVC与SpringBoot的区别
  • Docker续9:使用docker-compose部署nmt项目,在haproxy中代理mysql负载均衡
  • k8s的搭建
  • 【Clickhouse】Clickhouse数据库简介
  • mysql 日志恢复
  • Python数据分析与可视化基础教程
  • Linux系统下配置和测试Redis服务
  • 探索未来住宿体验:酒店触摸开关的科技魅力
  • 【API安全】威胁猎人发布超大流量解决方案
  • SVN的使用技巧
  • [机器学习]聚类算法
  • Servlet学习详解--基本涵盖所有Servlet知识点
  • 取消Cursor的注释斜体字风格
  • Java8函数式接口全攻略
  • 北大阿里:新出炉的LLM偏好对齐方法综述
  • SAP Fiori-Vscode 环境搭建中npm报错
  • Ansible使用kubeadm方式一键安装k8s
  • 跨越日语障碍2024轻松实现日语阅读的好帮手
  • 旅游网站设计与实现:SpringBoot技术手册
  • buildroot移植qt报错Info: creating stash file (补充qt添加字库)
  • 第 1 0 章OpenCV