美文网首页
Requests与BeautifulSoup的基本用法

Requests与BeautifulSoup的基本用法

作者: 逍遥_yjz | 来源:发表于2021-06-10 08:11 被阅读0次

1. Requests 库

1.1 抓取数据

import requests
# 封装头
my_headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36'
}

my_url = 'https://www.sogou.com/web'
# 处理url携带的参数:封装到字典中
my_param = {
    'query':'hi'
}
# 对指定的url发起的请求是携带参数的
response = requests.get(url=my_url, params=my_param, headers=my_headers)

page_text = response.text
print(page_text)

1.2 文件下载

1.2.1 第一种

如果要下载文件的话,就不能用response.text属性了,应该用response.content,区别如下

  • text 返回的是unicode 型的数据
  • content返回的是bytes,二级制型的数据。
    示例代码:下载图片
import requests
content = requests.get('http://image.nmc.cn/assets/img/w/40x40/4/0.png').content
# 写入文件
with open('0.png','wb') as fp:
    fp.write(content)

1.2.2 第二种

from urllib.request import urlretrieve
urlretrieve('http://image.nmc.cn/assets/img/w/40x40/4/0.png', '0.png')

2. BeautifulSoup库解析数据

lxml是BeautifulSoup的一种解析器,可以用来解析HTML代码。

下面使用的网页文件来自于alice.html,完整代码如下

<html>

<body>
    <p>html_doc = """
    </p>
    <title>The Dormouse's story</title>
    <p class="title"><b>The Dormouse's story</b></p>
    <p class="story">Once upon a time there were three little sisters; and their names were
        <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
        <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
        <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>; and they lived at the bottom of a well.</p>
    <p class="story">...</p>
    """</body>

</html>

2.1 加载对象到BeautifulSoup

有两种方法加载对象,一种是读取本地文件,另一种加载上述使用requests方法得到的response.text
两种方法分别如下

# 0. 引入库
from bs4 import BeaitifulSoup

# 1. 将本地html的数据加载到对象中
fp = open('alice.html', 'r', encoding='utf-8')
soup = BeautifulSoup(fp,'lxml')# 文件对象 解析器

# 2. 将网上的页面源代码加载到对象中
page_text = response.text
soup = BeautifulSoup(page_text, 'lxml')

# 按照标准缩进格式输出
print(soup.prettify())

2.2 寻找标签数据

标签就是TagName,也就是<div>, <head>, <p>, <a>这些东西,BeautifulSoup提供了很便捷的提取方法,能够使用户快速获得内容。

2.2.1 .TagName方法

使用将TagName替换成上述列出的标签,就可以返回找到的第一个标签值,如下图所示


2.2.2 soup.find(TagName)方法

与2.2.1的方法一样,都是返回第一个标签。

soup.find('a')

output >> <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>

2.2.2 soup.find_all(TagName)方法

返回拥有该标签的全部值。

soup.find_all('a')

output >> [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
 <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
 <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

2.2.3 soup.select(‘某种选择器’) ⭐️

该方法功能强大,可以花式取得几乎所有的标签。接下来介绍选择器的语法

2.2.3.1 标签选择器

标签选择器是最简单的一种,他的语法为标签名,实际使用结果如下

soup.select('title') 
output >> [<title>The Dormouse's story</title>]

2.2.3.2 类选择器

类也就是标签中的class属性,类选择器的语法为.类名
实际使用结果如下

soup.select('.sister')

output>>[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
 <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
 <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

2.2.3.3 id选择器

id也就是标签中的id属性,类选择器的语法为#id
实际使用结果如下

soup.select('#link1')

output >> [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]

2.2.3.4 组合查找

组合查找即和单独select标签名,类名,id名进行的原理是一样的,例如查找 p 标签中,id 等于 link1的内容,二者需要用空格分开,实际的使用结果如下

soup.select('p #link1')

output >> [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]

2.2.3.5 属性查找

属性也就是标签中的其他附加内容,属性需要用中括号括起来,由于属性和标签属于同一节点,所以中间不能加空格,否则会无法匹配到。使用的实例如下

soup.select('a[href="http://example.com/lacie"]')

output >> [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

2.2.3.6 层级查找⭐️

这里要介绍一下层级



假设红框是第一层级,那么所有并列的蓝框就都是第二层级,也就是相对于红框的单层级;黑框就是第三层级,也就是相对于红框的多层级。层级查找有两种语法,分别对应着单层级查找和多层级查找。

单层级的查找语法如下,注意>前后一定要有空格

# 标签1 > 标签2
soup.select('body > p')

多层级的查找语法如下,只需要标签中间有空格就行

# 标签1  标签2
soup.select('body a')

因此,如果直接用>查找多层级,是会失败的,如下面的运行结果

soup.select('body > a')

output >> []

2.3 提取标签属性or文本内容

2.3.1 提取属性

定位到标签后,直接使用[Name]就可以获取属性值,使用实例如下

soup.select('body a.sister')[0]['href']

output >> 'http://example.com/elsie'

也可以使用get方法获得属性值

for link in soup.find_all('a'):
    print(link.get('href'))
 
output >> http://example.com/elsie
http://example.com/lacie
http://example.com/tillie

2.3.2 提取文本

定位到标签后,直接使用两个属性一个方法.text/.string/.get_text(),其中

  • text/get_text()可以获得一个标签中所有的内容,包括当前标签的+子节点标签的
  • string只获得当前标签的文本内容
    使用实例如下
soup.select('body')[0].text
output >> 'html_doc = """\nThe Dormouse\'s story\nThe Dormouse\'s story\nOnce upon a time there were three little sisters; and their names were\nElsie,\nLacie and\nTillie;\nand they lived at the bottom of a well.\n...\n"""'

soup.select('body')[0].string
output >> None

3. 总结

3.1 bs4

环境的安装:
   pip install bs4
   pip install lxml
    
bs4的解析原理
   实例化一个BeautifulSoup的对象,并且将即将被解析的页面源码数据加载到该对象中
   调用BeautifulSoup对象中的相关属性和方法进行标签定位和数据提取

如何实例化BeautifulSoup对象呢?
   BeautifulSoup(fp,'lxml'):专门用作于解析本地存储的html文档中的数据
        
   BeautifulSoup(page_text,'lxml'):专门用作于将互联网上请求到的页面源码数据进行解析

3.2 bs4的基本语法

基础语法:
    soup = BeautifulSoup(page_text,'lxml')
    (1)根据标签名查找
        - soup.a   只能找到第一个符合要求的标签
    (2)获取属性
        - soup.a.attrs  获取a所有的属性和属性值,返回一个字典
        - soup.a.attrs['href']   获取href属性
        - soup.a['href']   也可简写为这种形式
    (3)获取内容
        - soup.a.string      获取a标签的直系文本
        - soup.a.text     这是属性,获取a子类的所有文本
        - soup.a.get_text()  这是方法,获取a标签子类的所有文本
       【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容
    (4)find:找到第一个符合要求的标签
        - soup.find('a')  找到第一个符合要求的
        - soup.find('a', title="xxx") 具有title=a属性的
        - soup.find('a', alt="xxx")
        - soup.find('a', class_="xxx")
        - soup.find('a', id="xxx")
    (5)find_all:找到所有符合要求的标签
        - soup.find_all('a')
        - soup.find_all(['a','b']) 找到所有的a和b标签
        - soup.find_all('a', limit=2)  限制前两个
    (6)根据选择器选择指定的内容
               select:soup.select('#feng')
        - 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
            - 层级选择器:
                div .dudu #lala .meme .xixi  下面好多级
                div > p > a > .lala          只能是下面一级
        select就是css选择器
        【注意】select选择器返回永远是列表,需要通过索引提取指定的对象

3.3 select 和 find 和findall

soup = BeautifulSoup(html, ‘lxml‘)
s = soup.select(‘div .lily‘)#select的写法和find有区别,select是标签和class都在一个字符串里,find是两个字符串,用逗号隔开
f = soup.find(‘div‘,class_ = ‘lily‘) #find只取第一个值,返回的是字符串
fa = soup.find_all(‘div‘,class_ = ‘lily‘)#find——all是全部的值和select一样,是一个列表
fal = soup.find_all(‘div‘,class_ = ‘lily‘,limit=1)#find——all是全部的值和select一样,是一个列表,加limit属性后只返回第一个
print(s)
print(f)
print(fa)
print(fal)
>>>

[<div class="lily" id="ben">大笨蛋</div>, <div class="lily" id="ben">是个大笨蛋吗?</div>]
<div class="lily" id="ben">大笨蛋</div>
[<div class="lily" id="ben">大笨蛋</div>, <div class="lily" id="ben">个大笨蛋吗?</div>]
[<div class="lily" id="ben">大笨蛋</div>]

属性定位:soup.find('tagName',attrName='value'),返回也是单数
        find_all:和find用法一致,但是返回值是列表
1. name参数的四种过滤器
  soup=Beautifulsoup('page','lxml')
    不带过滤器: print(soup.find_all())  #没有过滤,查找所有标签
    字符串过滤器: print (soup.find_all())  #字符串过滤器,即标签名
    列表: print(soup.find_(['a','b'])) #找到所有的a标签和b标签,任一即可
    正则: print(soup.find_all(re.complie('^b'))) #找到所有b开头的标签
    方法: def has_class_but_no_id(tag):
         return tag.has_attr('class') and not tag.has_attr('id')
         print(soup.find_all(has_class_but_no_id))
2、按照类名查找,注意关键字是class_,class_=value,value可以是五种选择器之一
    print(soup.find_all('a',class_='sister')) #查找类为sister的a标签 
    print(soup.find_all('a',class_='sister ssss')) #查找类为sister和sss的a标签,顺序错误也匹配不成功 
    print(soup.find_all(class_=re.compile('^sis'))) #查找类为sister的所有标签

3、attrs 
    print(soup.find_all('p',attrs={'class':'story'}))

4、text: 值可以是:字符,列表,True,正则 
    print(soup.find_all(text='Elsie')) 
    print(soup.find_all('a',text='Elsie'))  

5、limit参数:如果文档树很大那么搜索会很慢.如果我们不需要全部结果,可以使用 limit 参数限制返回结果的数量.效果与SQL中的limit关键字类似,
    当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果
    print(soup.find_all('a',limit=2))


6、recursive:调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False .
    print(soup.html.find_all('a'))
    print(soup.html.find_all('a',recursive=False))

7.  find和find_all一样

爬取三国演义的章节信息和文章内容
分析:

1.先获取三国演义的主页面,里面包含了三国演义的文章章节标题,每个文章的章节都是一个a标签,访问这个a标签,就能查看文章的内容
2.发送请求,请求三国演义的主界面
3.在三国演义的主页面的html源码中找到章节的标签位置,定位标签位置
4.拿到列表数据,循环列表,循环发送章节的内容的请求

import requests
from bs4 import BeautifulSoup   # 导入BeautifulSoup
url = 'http://www.shicimingju.com/book/sanguoyanyi.html'  #
headers={
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}
sg_list = requests.get(url=url,headers=headers).text
soup = BeautifulSoup(sg_list,'lxml')
content = soup.select('.book-mulu > ul > li > a')  #章节的标签
f = open('sanguo.txt','w',encoding='utf-8')
for i in content:
    new_url = 'http://www.shicimingju.com'+i['href']   #拼接标签的访问路径
    title = i.string
    detail = requests.get(url=new_url,headers=headers).text  #循环发送对文章内容的请求
    soup = BeautifulSoup(detail,'lxml')
    new_detail = soup.find('div',class_="chapter_content").text
    f.write(new_detail)
    print(title+'爬取成功')
f.close()

相关文章

网友评论

      本文标题:Requests与BeautifulSoup的基本用法

      本文链接:https://www.haomeiwen.com/subject/xexyeltx.html