[ tool ] 爬虫之beautifulsoup简单使用哦~

1,304 阅读4分钟

这是我参与8月更文挑战的第28天,活动详情查看: 8月更文挑战

微信公众号搜索 程序媛小庄 人生苦短 一起学Python

爬虫协议

robots.txt文件,上面写了是否允许爬取网站数据

bs4模块

  • 安装

pip3 install beautifulsoup4

  • 模块介绍

BeautifulSoup是一个解析库,可以从HTLML中提取数据的库

bs4爬取汽车之家新闻 --- bs4基本使用

import requests
from bs4 import BeautifulSoup

# 文本格式的html
response = requests.get('https://www.autohome.com.cn/news/1/#liststart')
# print(response.text)

'''
使用bs4对html进行解析
第一个参数:html文本
第二个参数:使用什么解析器,可以使用内置的html.parser,不需要安装第三方模块,或者使用第三方模块lxml(pip install lxml)
'''
soup = BeautifulSoup(response.text, 'lxml')

'''
查找class为article-wrapper的div
'''
div1 = soup.find(class_='article-wrapper')
# print(div)

'''
查找id为auto-channel-lazyload-article的div
'''
div2 = soup.find(id='auto-channel-lazyload-article')
# print(div)

'''
查找class是article的ul标签
'''
ul = soup.find(class_='article')
'''
继续寻找ul下的所有li
'''
li_list = ul.find_all(name='li')
for li in li_list:
    '''
    查找每个li下的东西
    '''
    title = li.find(name='h3')
    '''
    防止广告
    '''
    if title:
        title = title.text
        url='https:'+li.find('a').attrs.get('href')
        desc=li.find('p').text
        img='https:'+li.find(name='img').get('src')
        print('''
        新闻标题:%s
        新闻地址:%s
        新闻摘要:%s
        新闻图片:%s
        
        '''%(title,url,desc,img))

bs4使用

遍历文档树

直接通过标签名字选择,特点是速度快,但是如果存在多个相同的标签则只返回第一个

  • html文档准备
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p id="my_p" class="title">hello<b id="bbb" class="boldest">The Dormouse's story</b>
</p>

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

<p class="story">...</p>
"""
  • 文档容错能力,不是一个标准的html也能解析
# 上述html文档的html body标签并没有闭合
soup=BeautifulSoup(html_doc,'lxml')
  • 遍历文档树用法

获取标签内的数据

head = soup.head (head是标签对象)
print(head)

获取标签名称

print(head.name)

获取标签的属性,属性可能有多个,放在列表中

p = soup.body.p # 获取body标签下的p标签
print(p.attrs)  # 获取p标签的属性/id等
print(p.attrs.get('class'))  # 获取p标签的属性方式一,得到的结果是一个列表
print(p.get('class'))  # 获取p标签的属性方式方式二,得到的结果是一个列表
print(p['class'])  # 获取p标签的属性方式方式二,得到的结果是一个列表

嵌套选择

a=soup.body.a
print(a.get('id'))
# 子节点、子孙节点
print(soup.p.contents) #p下所有子节点
print(soup.p.children) #得到一个迭代器,包含p下所有子节点
print(list(soup.p.children)) #得到一个迭代器,包含p下所有子节点
# 父节点、祖先节点
print(soup.a.parent) #获取a标签的父节点(只有一个)
print(soup.p.parent) #获取p标签的父节点
print(soup.a.parents) #找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲...
print(list(soup.a.parents))#找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲...
print(len(list(soup.a.parents)))#找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲...
# 兄弟节点
print(soup.a.next_sibling) #下一个兄弟
print(soup.a.previous_sibling) #上一个兄弟

print(list(soup.a.next_siblings)) #下面的兄弟们=>生成器对象
print(list(soup.a.previous_siblings)) #上面的兄弟们=>生成器对象

搜索文档树

find 与 find_all

find():只返回找到的第一个

find_all():找到的所有

五种过滤器

  • 字符串过滤:过滤内容是字符串
a = soup.find(name='a')
print(a) # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
res = soup.find(id='my_p')
res=soup.find(class_='story')
res=soup.find(href='http://example.com/elsie')

res=soup.find(attrs={'id':'my_p'})
res=soup.find(attrs={'class':'story'})
  • 正则表达式
import re
re_b=re.compile('^b')
res=soup.find(name=re_b)
res=soup.find_all(name=re_b)
res=soup.find_all(id=re.compile('^l'))
  • 列表
# 得到所有的标签名字是body或者是b的标签的数据
res=soup.find_all(name=['body','b'])
# 得到有sister或者title属性的标签的数据
res=soup.find_all(class_=['sister','title'])
  • True 和 False
# 获取所有有名字的标签(获取所有标签)
res=soup.find_all(name=True)
# 获取有id的标签
res=soup.find_all(id=True)
# 获取没有id的标签
res=soup.find_all(id=False)
res=soup.find_all(href=True)
  • 方法--了解
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))
  • 其他方法---limit(限制查找的条数)
res=soup.find_all(name=True,limit=1)
print(res)
recursive(recursive递归查找,找子子孙孙)
res=soup.body.find_all(name='b ',recursive=False)
res=soup.body.find_all(name='p',recursive=False)
res=soup.body.find_all(name='b',recursive=True)
print(res)

css选择

更多选择器参考www.w3school.com.cn/cssref/css_…

res = soup.select('#my_p')
ret=soup.select('body p')  # 子子孙孙
ret=soup.select('body>p')  # 直接子节点(儿子)
ret=soup.select('body>p')[0].text  # 直接子节点(儿子)
res = soup.select('#my_p')[0].attrs # 获取属性
res = soup.select('#my_p')[0].get_text() # 获取内容
res = soup.select('#my_p')[0].text # 获取内容
res = soup.select('#my_p')[0].strings # 子子孙孙的内容放到生成器中
对象.string # 当前标签下有文本才取出否则是None

总结

  • 推荐使用lxml解析库

  • 讲了三种选择器:标签选择器,find与find_all, css选择器

    ​ 标签选择器筛选能力弱

    ​ 简易使用find find_all查询匹配单个结果或者多个结果

    ​ 如果对css选择器非常熟悉建议使用select

  • 记住常用的获取属性attrs和获取内容的get_text()/text方法。

结语

文章首发于微信公众号程序媛小庄,同步于掘金

码字不易,转载请说明出处,走过路过的小伙伴们伸出可爱的小指头点个赞再走吧(╹▽╹)