美文网首页
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