zoukankan      html  css  js  c++  java
  • beautifulSoup模块

    beautifulSoup模块

    在之前的爬虫程序中 我们编写了大量的正则表达式来获取数据,效率非常低
    beautifulSoup是一个第三方模块  专门用于解析XML文档
    目前最稳定的是bs4 版本
    pip install bs4

    查找元素

    1.bs遍历文档树

    from bs4 import BeautifulSoup
    
    # 第一个参数为要解析的文档数据 可以是字符串 也可以是一个文件对象
    # 第二个参数表示要使用的解析器  每个解析器有不同的特点  推荐是用lxml 速度快 pip install lxml
    soup = BeautifulSoup(html_doc,"lxml")
    soup代表整个文档
    
    #查找内容
    tag = soup.body # 拿到html中body标签
    # 一个标签分为三个部分
    # 标签名字  标签属性  标签内容
    print(type(tag)) #Tag
    print(tag.name)  #标签名
    print(tag.text)  #标签内容
    print(tag.attrs) #标签属性  返回是一个字典
    
    # 使用点语法来查找标签   要注意 查找范围是全文 只能找到第一个名字匹配的标签
    tag = soup.a  #拿到第一个a标签
    print(tag.attrs.get("href")) #拿到属性href的内容
    
    # 嵌套选择
    print(soup.p.b.text)  #p标签中b标签的文本内容
    
    # 获取子节点
    #注意:a标签,还有img标签不能放到head标签中
    for i in soup.p.children:  # 返回一个迭代器 iterator
         print(i)
    
    for i in soup.p.contents: # 返回一个列表 
        print(i)
        
    # 获取父标签
    print(soup.p.parent)
    
    # 获取所有的父辈标签
    #soup.p.parents #返回一个生成器 generator
    for i in soup.p.parents:
        print(i.name)
        
    
    # 获取所有子孙标签 与soup.p.contents不同之处在于 会把所有子孙标签全部拆出来 包括文本内容
    #soup.p.descendants #返回一个生成器 generator
    for i in soup.p.descendants:
        print(i.name) # 文本内容没有name属性,返回None
        
    # 获取兄弟标签 文本也被当做是一个节点
    # 下一个兄弟
    print(soup.a.next_sibling)
    # 之后的兄弟们
    print(list(soup.a.next_siblings))
    
    # 上一个兄弟
    print(soup.a.previous_sibling)
    # 之前的兄弟们
    print(list(soup.a.previous_siblings))

    2.bs搜索文档树

    1.find_all()

    # 过滤器
    # find_all查找所有匹配的标签
    # 按照名字匹配   可以传一个名字 或 一个列表
    print(soup.find_all("a"))  #查找所有的a标签
    print(soup.find_all(["a","p"])) #查找所有的a和p标签
    
    # 找id 为link 的a标签
    print(soup.find_all("a",attrs={"id":"link"}))
    print(soup.find_all(name="a",id="link"))
    
    # 找class为sister 的a标签
    print(soup.find_all("a",attrs={"class":"sister"}))
    
    # 注意如果要按照条件为class来查找 需要使用class_ 因为class是关键字
    print(soup.find_all(name="a",class_="sister brother")) # 只能找到类名完全匹配的如:<a class="sister brother">
    
    print(soup.find_all(name="a",class_="sister")) #只要类名带有sister就能找到
    
    # 如果属性带有特殊符号 可以把条件装在attrs中
    print(soup.find_all(name="a",attrs={"data-a":"sister"}))
    
    
    # 指定文本
    print(soup.find_all(name="a",text="Elsie"))
    
    
    # 过滤器
    # 标签名称中带有b字母的标签
    # 正则匹配
    c = re.compile("b")
    print(soup.find_all(name=c))
    
    
    # 列表
    print(soup.find_all(name=["body","a"]))
    
    
    # True 表示所有标签
    print(soup.find_all(True))
    
    # 所有具备id属性的标签
    print(soup.find_all(id=True))
    
    
    # 方法匹配(写个函数来过滤)
    def myFilter(tag):# 必须只能有一个参数 参数表示要过滤的标签
        #标签名是a  文本内容不是"Elsie" 标签含有id属性 
        return tag.name == "a" and tag.text != "Elsie" and tag.has_attr("id")
    print(soup.find_all(myFilter)) #返回满足条件的所有数据
    print(soup.find_all(myFilter,limit=1))  #返回一条数据
    
    #获取所有a标签
    print(soup.find_all(name="a"))
    
    
    # 五种过滤器: 字符串、正则表达式、列表、True、方法

    2.find()

    #find( name , attrs , recursive , text , **kwargs )
    find_all() 方法将返回文档中符合条件的所有tag,尽管有时候我们只想得到一个结果.比如文档中只有一个<body>标签,那么使用 find_all() 方法来查找<body>标签就不太合适, 使用 find_all 方法并设置 limit=1 参数不如直接使用 find() 方法.下面两行代码是等价的:
    
    soup.find_all('title', limit=1)
    # [<title>The Dormouse's story</title>]
    soup.find('title')
    # <title>The Dormouse's story</title>
    
    唯一的区别是 find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果.
    find_all() 方法没有找到目标是返回空列表, find() 方法找不到目标时,返回 None .
    
    soup.head.title 是 tag的名字 方法的简写.这个简写的原理就是多次调用当前tag的 find() 方法:
    
    soup.head.title
    # <title>The Dormouse's story</title>
    soup.find("head").find("title")
    # <title>The Dormouse's story</title>
    
    # recursive 是否递归

    3、CSS选择器

    #该模块提供了select方法来支持css,详见官网:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#id37
    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title">
        <b>The Dormouse's story</b>
        Once upon a time there were three little sisters; and their names were
        <a href="http://example.com/elsie" class="sister" id="link1">
            <span>Elsie</span>
        </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>;
        <div class='panel-1'>
            <ul class='list' id='list-1'>
                <li class='element'>Foo</li>
                <li class='element'>Bar</li>
                <li class='element'>Jay</li>
            </ul>
            <ul class='list list-small' id='list-2'>
                <li class='element'><h1 class='yyyy'>Foo</h1></li>
                <li class='element xxx'>Bar</li>
                <li class='element'>Jay</li>
            </ul>
        </div>
        and they lived at the bottom of a well.
    </p>
    <p class="story">...</p>
    """
    from bs4 import BeautifulSoup
    soup=BeautifulSoup(html_doc,'lxml')
    
    #1、CSS选择器
    print(soup.p.select('.sister'))
    print(soup.select('.sister span'))
    
    print(soup.select('#link1'))
    print(soup.select('#link1 span'))
    
    print(soup.select('#list-2 .element.xxx'))
    
    print(soup.select('#list-2')[0].select('.element')) #可以一直select,但其实没必要,一条select就可以了
    
    # 2、获取属性
    print(soup.select('#list-2 h1')[0].attrs)
    
    # 3、获取内容
    print(soup.select('#list-2 h1')[0].get_text())

    案例:爬取汽车之家新闻

    import requests
    from bs4 import BeautifulSoup
    
    url = "https://www.autohome.com.cn/news/{page}/"
    
    # 过滤标签
    def filter(tag):
        return tag.name == "li" and tag.has_attr("data-artidanchor")
    
    # 获取新闻列表
    def get_list_paget(url):
        print(url)
        resp = requests.get(url,headers={"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36"})
    
        soup = BeautifulSoup(resp.text,"lxml")
        lis = soup.find_all(filter)
        for t in lis:
            print("https:"+t.a.attrs.get("href"))
            print("https:"+t.img.attrs.get("src"))
            print(t.h3.text)
            print(t.span.text)
            print(t.em.text)
            print(t.p.text)
    
    get_list_paget(url.format(page = 1))

    案例:爬取中关村测评数据

    '''
    分析可知
    1.首页数据存放在html文档中
    http://labs.zol.com.cn/
    
    2.后续加载的数据是通过ajax请求,刷新文档,返回数据类型为json
    http://labs.zol.com.cn/router.php?c=TestChannel_Default&a=GetChannelNew&module=new&page=2
    '''
    
    import requests
    from bs4 import  BeautifulSoup
    
    #爬取第一页的数据
    url = 'http://labs.zol.com.cn/'
    user_agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
    
    resp = requests.get(url,headers = {'user-agent':user_agent})
    soup = BeautifulSoup(resp.text,'lxml')
    
    res = soup.find_all(name='li',class_='content-list-item')
    for i in res:
        #连接
        print(i.a.get('href'))
    
        #标题
        print(i.div.div.text)
    
        #简介
        print(i.p.text)
    
        #评论数
        n = i.find(name='div',class_='icon info-comment')
        print(n.text)
    
        #时间
        print(i.span.text)
    
        #单张图片获取
        print(i.a.img.attrs.get('src'))
        #多张图片获取
        res = i.find(True,class_='pics-list clearfix')
        if res:
            imgs = i.find_all(name='img')
            for img in imgs:
                print(img.attrs.get('src'))
    
    import time
    #爬取加载更多的数据
    base_url = 'http://labs.zol.com.cn/router.php?c=TestChannel_Default&a=GetChannelNew&module=new&page={page}'
    for i in range(2,4): #爬取第二页和第三页的数据
        resp = requests.get(base_url.format(page=i))
        print(resp.json())
        time.sleep(1)
  • 相关阅读:
    fishredux 大体流程
    flutter Container组件和Text组件
    vue 页面跳转以及传参
    mySql 查询当天、本周、最近7天、本月、最近30天的语句
    Flutter编译时下载依赖报错的解决方案
    计算属性和方法
    计算属性传参
    原生js发送请求
    MySQL数据库连接
    flask 蓝图
  • 原文地址:https://www.cnblogs.com/lizeqian1994/p/10751141.html
Copyright © 2011-2022 走看看