文章目录

  • 简介
    • 安装
    • 本文示例的html代码
  • 用法
    • 实例化对象
    • bs表达式
      • 四大对象种类
        • Tag
        • NavigableString
        • BeautifulSoup
        • Comment
      • 搜索文档树
        • find_all
          • name 参数
            • 传字符串
            • 传正则表达式
            • 传列表
            • 传 True
            • 传方法
          • attrs 参数
          • text 参数
          • limit 参数
          • recursive 参数
        • find
      • CSS选择器
        • 通过标签名查找
        • 通过类名查找
        • **通过 id 名查找**
        • **组合查找**
        • **属性查找**
  • 案例

简介

Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据

官方解释

  • Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。

  • Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时,Beautiful Soup就不能自动识别编码方式了。然后,你仅仅需要说明一下原始编码方式就可以了。

  • Beautiful Soup已成为和lxml、html6lib一样出色的python解释器,为用户灵活地提供不同的解析策略或强劲的速度。

安装

pip install bs4

本文示例的html代码

<div><div><ul><li class="item-0"><a href="link1.html"><!--这是一个注释--></a></li><li class="item-1"><a href="link2.html">second item</a></li></ul></div><div id="111"><div class="item-1"><a href="www.qq.com">qq.com</a><p>this is p label</p><ul><li class="item-2"><a href="link1.html">first item1</a></li><li class="item-3"><a href="link2.html">second item2</a></li></ul></div><a href="www.baidu.com">baidu.com</a></div>
</div>

用法

实例化对象

from bs4 import BeautifulSoup# 将互联网上获取的源码数据加载到该对象中
soup = BeautifulSoup(resp.text, 'lxml')
# 将本地的html文件加载etree对象中
soup = BeautifulSoup(open("file_path"))soup.prettify()  # 格式化html文件

bs表达式

四大对象种类

Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:

  • Tag:标签
  • NavigableString:文本
  • BeautifulSoup
  • Comment

Tag

用 BeautifulSoup 可以很方便地获取 Tags

print(soup.li)  # 获取第一个符合的li标签
print(soup.head)  # 获取头部标签内的代码

对于 Tag,它有两个重要的属性,name 和 attrs

print(soup.li.name)  # 输出li
print(soup.name)  # soup实质为一个文档
print(soup.li["class"])  # 输出li标签内,class属性的值,即等号后面的值
print(soup.li.get("class"))  # 等价

NavigableString

既然我们得到了标签内容,我们就可以获取标签内部的文字

print(soup.a.string)
print(type(soup.a.string))

BeautifulSoup

BeautifulSoup 对象表示的是一个文档的全部内容.大部分时候,可以把它当作 Tag 对象,是一个特殊的 Tag,我们可以分别获取它的类型,名称以及属性

print(type(soup))
print(soup.string)
print(soup.attrs)

Comment

Comment 对象是一个特殊类型的 NavigableString 对象,其实输出的内容仍然不包括注释符号,但是如果不好好处理它,可能会对我们的文本处理造成意想不到的麻烦

print(soup.a.string)  # 输出“这是一个注释”为comment类型
if type(soup.a.string)==bs4.element.Comment:print(soup.a.string)  # 通过这个来判断是否为注释

搜索文档树

find_all

( name , attrs , recursive , text , **kwargs )

name 参数
传字符串

最简单的过滤器是字符串.在搜索方法中传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容,

print(soup.find_all("li"))  # 查找文档中所有的\<li>标签
传正则表达式

如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的 match() 来匹配内容

print(soup.find_all(re.compile("^b")))  # 匹配所有以b开头的标签
传列表

如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回

print(soup.find_all(["li", "a"]))  # 找到所有的li标签和a标签
传 True

True 可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点

print(soup.find_all(True))
传方法

如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数,如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则返回 False

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))
attrs 参数

如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索,如果包含一个名字为 id 的参数,Beautiful Soup会搜索每个tag的”id”属性

soup.find_all(id='111')

如果传入 href 参数,Beautiful Soup会搜索每个tag的”href”属性

soup.find_all(href=re.compile("link"))

使用多个指定名字的参数可以同时过滤tag的多个属性

soup.find_all(href=re.compile("link"), id='111')

如果标签名和python中的关键字重合

soup.find_all(attrs={"class"; "item-0"})  # 字典传参
soup.find_all(class_="item-0")  # 等价
text 参数

通过 text 参数可以搜搜文档中的字符串内容.与 name 参数的可选值一样, text 参数接受 字符串 , 正则表达式 , 列表, True

soup.find_all(text="first item1")
limit 参数

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

print(soup.find_all("li", limit=3))
recursive 参数

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

print(soup.find_all("li", limit=3, recursive=False))

find

( name , attrs , recursive , text , **kwargs )

它与 find_all() 方法唯一的区别是 find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果

CSS选择器

我们在写 CSS 时,标签名不加任何修饰,类名前加点,id名前加 #,在这里我们也可以利用类似的方法来筛选元素,用到的方法是 soup.select(),返回类型是 list

通过标签名查找
print(soup.select('li'))
通过类名查找
print(soup.select('.item-0'))  # 注意要加点
通过 id 名查找
print(soup.select('#111'))
组合查找

组合查找即和写 class 文件时,标签名与类名、id名进行的组合原理是一样的,例如查找 p 标签中,id 等于 link1的内容,二者需要用空格分开

print(soup.select('li' ".item-0"))

直接子标签查找

print(soup.select("li > a"))
属性查找

查找时还可以加入属性元素,属性需要用中括号括起来,注意属性和标签属于同一节点,所以中间不能加空格,否则会无法匹配到

print(soup.select('a[href="link2.html"]'))

案例

import threading, queue"""爬虫多线程"""class SpiderThread(threading.Thread):def __init__(self) -> "里面包含了请求头和代理IP 代理ip自己设置":super().__init__(daemon=True)  # daemon线程等待,target是运行的函数# 开启队列对象self.queue = queue.Queue()# 线程self.start()  # 实例化的时候自动运行run函数try:# 构建ip池,此ip地址仅支持http请求file = open("./ip.txt", "r")  # 得到大量ip地址,与文件同一目录下,存储http类型的ip池ipList = file.readlines()file.close()import randomself.ip = random.choice(ipList).strip()except Exception as e:print(f"没有批量ip地址,使用本机ip地址{e}")import sockets = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)s.connect(('8.8.8.8', 80))import randomself.ip = s.getsockname()[0] + f":{random.randint(1, 8080)}"  # 获取本电脑的ip地址,同时随机使用端口访问网址s.close()# 传入requests所需要的参数self.headers = {'User-Agent': "Mozilla / 5.0(Windows NT 10.0;Win64;x64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 96.0.4664 .93 Safari / 537.36"}self.proxy = {"http": f"https://{self.ip}",# 注意:如果请求的ip是https类型的,但代理的ip是只支持http的,那么还是使用本机的ip,如果请求的ip是http类型的,那么代理的ip一定要是http的,前面不能写成https,否则使用本机IP地址}def run(self) -> None:  # run方法线程自带的方法,内置方法,在线程运行时会自动调用while True:  # 不断处理任务func, args, kwargs = self.queue.get()func(*args, **kwargs)  # 调用函数执行任务 元组不定长记得一定要拆包self.queue.task_done()  # 解决一个任务就让计数器减一,避免阻塞# 生产者模型def submit_task(self, func, args=(), kwargs={}):  # func为要执行的任务,加入不定长参数使用(默认使用默认参数)self.queue.put((func, args, kwargs))  # 提交任务# 重写join方法def join(self):self.queue.join()  # 查看队列计时器是否为0 任务为空 为空关闭队列def crawl(url, lis, cookies=None, headers=SpiderThread().headers,proxy=SpiderThread().proxy) -> "lis用来存储返回的resp响应 其是发送get请求":  # cookies是一个字典import requestsif not isinstance(cookies, dict):resp = requests.get(url=url, headers=headers, proxies=proxy)else:resp = requests.get(url=url, headers=headers, cookies=cookies)if resp.status_code == 200:print("获取完成,返回的数据在传入的列表里面")lis.append(resp)  # 多线程没有返回值else:SpiderThread().submit_task(crawl, args=(i, lis))
# 爬取58同城中全国销售职位的名称
from bs4 import BeautifulSoup
import MyModule
from concurrent.futures import ThreadPoolExecutorspider = MyModule.SpiderThread()  # 实例化爬虫对象"""
通过分析url可得到 url = 'https://nc.58.com/yewu/pu1/?key=%E9%94%80%E5%94%AE';
又第二页的        url = 'https://nc.58.com/yewu/pn2/?key=%E9%94%80%E5%94%AE'
"""# 得到所有页面的url
def spider1():resp = []  # 接收返回的页面源代码url = "https://nc.58.com/yewu/?key=%E9%94%80%E5%94%AE"spider.submit_task(MyModule.crawl, args=(url, resp))spider.join()  # 等待线程完成page_source = resp[0].text  # 得到页面源码html = BeautifulSoup(page_source, "lxml")  # 实例化bs对象num = int(html.find("span", attrs={"class": "total_page"}).string)return [f"https://nc.58.com/yewu/pn{i}/?key=%E9%94%80%E5%94%AE" for i in range(1, num)]def crawl():respAll = []  # 存储响应for i in spider1():spider.submit_task(MyModule.crawl, args=(i, respAll))  # 运行封装的模块spider.join()  # 等待全部线程完成return [i.text for i in respAll]  # 返回响应源代码def save(resp_text):html = BeautifulSoup(resp_text, "lxml")import retorr = html.find_all("li", class_=re.compile("job_item"))file = open("./a.txt", "a+", encoding="utf-8")  # 写入文件for i in torr:name = "".join([j.string for j in i.find_all("span", limit=2)])file.write(f"名称:{name}")file.close()def main(respAll):with ThreadPoolExecutor(50) as pool:  # 使用线程池,开启50个线程,对文件进行存储pool.map(save, respAll)if __name__ == '__main__':main(crawl())  # 注意:由于是高性能爬虫,电脑的ip地址很大概率会被58同城封了,尽量使用代理ip

Python中bs解析相关推荐

  1. python中getitem_解析Python中的__getitem__专有方法

    __getitem__来看个简单的例子就明白: def __getitem__(self, key): return self.data[key] >>> f = fileinfo. ...

  2. python中xml解析sax_python使用SAX解析xml

    python 标准库包含SAX解析器,SAX用事件驱动模型,通过在解析XML的过程中触发一个个的事件并调用用户定义的回调函数来处理XML文件 在python中使用sax方式处理xml要先引入xml.s ...

  3. Python中bs包的使用

    1.导入模块 from bs4 import BeautifulSoup 2.解析获取到的网页内容 文档被转换成Unicode,并且HTML的实例都被转换成Unicode编码. 可以打印soup对象的 ...

  4. python中bs包的使用方法

    Beautifulsoup简介 简单来说,BeautifulSoup就是Python的一个HTML或XML的解析库,我们可以用它来方便地从网页中提取数据,官方的解释如下: BeautifulSoup提 ...

  5. python中ht_python – 解析HTSQL时处理语法歧义

    我正在编写一个语法来解析HTSQL语法,并坚持如何处理段和除法运算符的/字符重用. described grammar并不是非常正式,所以我一直在关注Python实现的确切输出,从粗略的一瞥似乎是一个 ...

  6. Python中jmespath解析提取json数据

    在做接口自动化,测试断言时,我们经常需要提取接口的的响应数据字段,以前用过jsonpath,有几篇相关文章,可以参考下(Python深层解析json数据之JsonPath.[Jmeter篇]后置处理器 ...

  7. Python 中的解析命令行参数

    argparse argparse 是 Python 内置的一个用于命令项选项与参数解析的模块,通过在程序中定义好我们需要的参数,argparse 将会从 sys.argv 中解析出这些参数,并自动生 ...

  8. Python中歌词解析

    分析: 1.对于歌词解析这个事情,本质上就是对字符串进行切片. 2.首先要讲时间与歌词分开 3.将时间的24时格式转为数字形式,作为字典的key,而歌词作为字典的value 可以直接使用:dict[k ...

  9. 小白对python中网页解析库pyquery的理解

    终于又开始写一些基本的东西,借博客来记录一下自己的学习过程 在不断深入研究python爬虫后,学到了越来越多的东西,对于爬虫解析网页的多种方法也有了一定的理解,之前讲过beautifulsoup的一些 ...

最新文章

  1. 用python解“BCD解密”问题
  2. 使用帮助   history 用法   echo输出闪烁作业
  3. AGG第二十课 agg::ellipse 方法approximation_scale()
  4. proxool配置多数据库多连接池
  5. AOP与OOP的区别
  6. 点对点 客户端-服务器 聊天程序
  7. ASP.Net请求处理机制初步探索之旅 - Part 1 前奏
  8. js计算排名_今天,我们讲一下,快速排名与黑帽SEO
  9. 21天jmeter打卡day3-熟悉界面
  10. Hibenate连接mysql错误_hibernate连接数据库问题,注意是表名的大小写
  11. C语言volatile的本质(三十四)
  12. JS 新浪API获取IP归属地
  13. 北大飞跃手册_【通知】关于转发吉林大学大学生飞跃社团2020年吉林大学飞跃手册预发布会即将召开!...
  14. python在线编辑器
  15. 喜欢蓝蓝的天空白白的云。这首《 Blue Skies》就是啦。
  16. ORA-00932:数据类型不一致,应为-,但却获得BLOB类型
  17. 【Paper】WISDM:Activity Recognition using Cell Phone Accelerometers
  18. html如何让网页全屏,如何把页面弄成全屏?
  19. 按照分类方法判断图片里是否有鹅蛋
  20. C sharp (#) 数据类型获取

热门文章

  1. 使用MindStudio完成ch_ppocr_mobile_v2.0_cls模型开发
  2. 站群服务器做站群后,如何做SEO?
  3. 超越 —— 零点乐队
  4. 服务器的标准pcb型号,服务器电源的标准
  5. (转)用宏获取函数名
  6. 第38篇:和骏君清华大学聊区块链
  7. SqlBulkCopy与临时表、普通Sql操作配合使用
  8. 淘宝将全面屏蔽外链二维码 伤及无辜的是卖家
  9. 最新30个优秀的旅行网站设计作品欣赏
  10. 微信小程序丝滑的tab栏