• python3 爬虫相关-requests和BeautifulSoup


    前言

    时间的关系,这篇文章只记录了相关库的使用,没有进行深入分析,各位看官请见谅(还是因为懒。。。。。)

    requests使用

    发送无参数的get请求

    r = requests.get('http://httpbin.org/get')
    print(r.text)
    

    发送带参数的get请求

    load = {'key1': 'value1', 'key2': 'value2'}
    r = requests.get("http://httpbin.org/get",params = load)
    print(r.url)
    u'http://httpbin.org/get?key2=value2&key1=value1'
    

    发送带参数的post请求

    想要发送一些编码为表单形式的数据,表现形式非常像一个HTML表单。要实现这个,只需简单地传递一个字典给 data 参数。你的数据字典 在发出请求时会自动编码为表单形式。

    load = {'key1': 'value1', 'key2': 'value2'}
    r = requests.post("http://httpbin.org/post", data=load)
    print(r.text)
    
    {
      ...
      "form": {
        "key2": "value2",
        "key1": "value1"
      },
      ...
    }
    

    很多时候你想要发送的数据并非编码为表单形式的。如果你传递一个string而不是一个dict,那么数据会被直接发布出去。

    例如,Github API 3接受编码为JSON的POST/PATCH数据:

    >>> url = 'https://api.github.com/some/endpoint'
    >>> load = {'some': 'data'}
    >>> r = requests.post(url, data=json.dumps(load))
    

    发送文件的post类型

    这个相当于向网站上传一张图片,文档等操作,这时要使用files参数

    url = 'http://httpbin.org/post'
    files = {'file': open('touxiang.png', 'rb')}
    r = requests.post(url, files=files)
    

    定制headers,使用headers参数来传递

    url = 'https://api.github.com/some/endpoint'
    load = {'some': 'data'}
    headers = {'content-type': 'application/json'}
    r = requests.post(url, data=json.dumps(load), headers=headers)
    

    编码类型

    可以找出Requests使用了什么编码,并且能够改变它

    r.encoding
    'utf-8'
    r.encoding = 'ISO-8859-1'
    

    如果改变了编码,每当访问r.text时,Request都将会使用r.encoding的新值。

    响应内容

    响应状态码

    r = requests.get(‘http://httpbin.org/get‘)
    print(r.status_code)
    

    响应头

    print(r.headers)
    

    也可以取到这个个别的响应头用来做一些判断,这里的参数是不区分大小写的

    r.headers[‘Content-Type’]
    r.headers.get(‘Content-Type’)
    

    响应内容

    # 被encoding解码后内容
    r.text
    # 以字节的方式访问请求响应体
    r.content
    

    获取响应中的cookies

    r = requests.get('http://www.baidu.com')
    r.cookies['BAIDUID']
    

    也可以自已定义请求的COOKIES

    url = 'http://httpbin.org/cookies'
    cookies = {'cookies_are':'working'}
    r = requests.get(url,cookies = cookies)
    print(r.text)
    {
      "cookies": {
        "cookies_are": "working"
      }
    }
    

    设置超时时间

    requests.get('http://github.com', timeout=1)
    

    访问中使用session

    先初始化一个session对象

    s = requests.Session()
    

    然后使用这个session对象来进行访问

    r = s.post(url,data = user)
    

    JSON相应内容

    requests中也有一个内置的JSON解码器,助你处理JSON数据

    r = requests.get('https://github.com/timeline.json')
    r.json()
    [{u'repository': {u'open_issues': 0, u'url': 'https://github.com/...
    

    如果JSON解码失败,r.json就会抛出一个异常

    原始响应内容

    在罕见的情况下你可能想获取来自服务器的原始套接字响应,那么你可以访问r.raw 如果你确实想这么干,那请你确保在初始请求中设置了stream=True

    >>> r = requests.get('https://github.com/timeline.json', stream=True)
    >>> r.raw
    <requests.packages.urllib3.response.HTTPResponse object at 0x101194810>
    >>> r.raw.read(10)
    'x1fx8bx08x00x00x00x00x00x00x03'
    

    错误与异常

    遇到网络问题(如:DNS查询失败、拒绝连接等)时,Requests会抛出一个ConnectionError 异常。

    遇到罕见的无效HTTP响应时,Requests则会抛出一个 HTTPError 异常。

    若请求超时,则抛出一个 Timeout 异常。

    若请求超过了设定的最大重定向次数,则会抛出一个 TooManyRedirects 异常。

    所有Requests显式抛出的异常都继承自 requests.exceptions.RequestException 。

    Beautiful Soup使用方法

    创建 beautifulsoup 对象

    soup = BeautifulSoup(html)
    

    另外,我们还可以用本地 HTML 文件来创建对象,例如

    soup = BeautifulSoup(open('index.html'))
    

    上面这句代码便是将本地 index.html 文件打开,用它来创建 soup 对象

    下面我们来打印一下 soup 对象的内容,格式化输出

    print(soup.prettify())
    

    四大对象种类

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

    • Tag
    • NavigableString
    • BeautifulSoup
    • Comment
    Tag

    Tag 通俗点讲就是 HTML 中的一个个标签

    打印标题标签内容

    print(soup.title)
    #<title>The Dormouse's story</title>
    

    打印属性

    print(soup.a.attrs)
    {'href': '#main', 'class': ['skip-link', 'screen-reader-text']}
    

    打印特定属性

    print(soup.a['class'])
    ['skip-link', 'screen-reader-text']
    或者
    print(soup.a.get('href'))
    #main
    

    修改属性

    soup.a['href']='#'
    print(soup.a)
    
    <a class="skip-link screen-reader-text" href="#">Skip to content</a>
    

    删除属性

    del soup.a['class']
    print(soup.a)
    
    <a href="#main">Skip to content</a>
    

    用 .string 即可获取标签内部的文字,它的类型是一个NavigableString

    print(soup.a.string)
    
    Skip to content
    
    BeautifulSoup

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

    Comment

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

    遍历文档树

    直接子节点
    • .contents

      tag 的 .content 属性可以将tag的子节点以列表的方式输出

      print(soup.a.contents)
      
      ['Skip to content']
      
    • .children

      它返回的不是一个list,不过我们可以通过遍历获取所有子节点。

      我们打印输出.children看一下,可以发现它是一个list生成器对象

    所有子孙节点

    .descendants

    .contents和.children属性仅包含tag的直接子节点,.descendants属性可以对所有tag的子孙节点进行递归循环,和children类似,我们也需要遍历获取其中的内容。

    for child in soup.descendants:
        print("------->")
        print(child)
    
    节点内容

    如果tag只有一个NavigableString类型子节点,那么这个tag可以使用.string得到子节点。如果一个tag仅有一个子节点,那么这个tag也可以使用.string方法,输出结果与当前唯一子节点的.string 结果相同。

    如果tag包含了多个子节点,tag就无法确定,string方法应该调用哪个子节点的内容,.string的输出结果是None

    多个内容

    .strings获取多个内容,不过需要遍历获取

    for string in soup.head.strings:
        print("------->")
        print(string)
    

    .stripped_strings

    输出的字符串中可能包含了很多空格或空行,使用.stripped_strings可以去除多余空白内容

    for string in soup.head.stripped_strings:
        print("------->")
        print(string)
    
    父节点
    p=soup.p
    print(p.parent.name)
    
    全部父节点

    .parents

    通过元素的.parents属性可以递归得到元素的所有父辈节点,例如

    p=soup.p
    for parent in p.parents:
        print('------->')
        print(parent.name)
    
    兄弟节点

    兄弟节点可以理解为和本节点处在统一级的节点,.next_sibling属性获取了该节点的下一个兄弟节点,.previous_sibling则与之相反,如果节点不存在,则返回None

    注意:实际文档中的tag的.next_sibling和.previous_sibling属性通常是字符串或空白,因为空白或者换行也可以被视作一个节点,所以得到的结果可能是空白或者换行

    全部兄弟节点

    通过.next_siblings和.previous_siblings属性可以对当前节点的兄弟节点迭代输出

    前后节点

    .next_element和.previous_element属性,与.next_sibling和.previous_sibling不同,它并不是针对于兄弟节点,而是在所有节点,不分层次

    所有前后节点

    通过.next_elements和.previous_elements的迭代器就可以向前或向后访问文档的解析内容,就好像文档正在被解析一样

    搜索文档树

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

    find_all() 方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件

    1. name 参数

    name参数可以查找所有名字为name的tag,字符串对象会被自动忽略掉

    1. keyword 参数

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

    3.text 参数

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

    4.limit 参数

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

    5.recursive 参数

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

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

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

    find_parents()/find_parent()

    find_all() 和 find() 只搜索当前节点的所有子节点,孙子节点等. find_parents() 和 find_parent() 用来搜索当前节点的父辈节点,搜索方法与普通tag的搜索方法相同,搜索文档搜索文档包含的内容

    find_next_siblings()/find_next_sibling()

    这2个方法通过 .next_siblings 属性对当 tag 的所有后面解析的兄弟 tag 节点进行迭代, find_next_siblings() 方法返回所有符合条件的后面的兄弟节点,find_next_sibling() 只返回符合条件的后面的第一个tag节点

    find_previous_siblings()/find_previous_sibling()

    这2个方法通过 .previous_siblings 属性对当前 tag 的前面解析的兄弟 tag 节点进行迭代, find_previous_siblings() 方法返回所有符合条件的前面的兄弟节点, find_previous_sibling() 方法返回第一个符合条件的前面的兄弟节点

    find_all_next()/find_next()

    这2个方法通过 .next_elements 属性对当前 tag 的之后的 tag 和字符串进行迭代, find_all_next() 方法返回所有符合条件的节点, find_next() 方法返回第一个符合条件的节点

    find_all_previous() 和 find_previous()

    这2个方法通过 .previous_elements 属性对当前节点前面的 tag 和字符串进行迭代, find_all_previous() 方法返回所有符合条件的节点, find_previous()方法返回第一个符合条件的节点

    CSS选择器

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

    1. 通过标签名查找
    print soup.select('title') 
    #[<title>The Dormouse's story</title>]
    
    print soup.select('a')
    #[<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>]
    
    print soup.select('b')
    #[<b>The Dormouse's story</b>]
    
    1. 通过类名查找
    print soup.select('.sister')
    #[<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>]
    
    1. 通过 id 名查找
    print soup.select('#link1')
    #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]
    
    1. 组合查找
      组合查找即和写css文件时,标签名与类名、id名进行的组合原理是一样的,例如查找p 标签中,id等于link1的内容,二者需要用空格分开
    print soup.select('p #link1')
    #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]
    

    直接子标签查找
    print soup.select("head > title")

    [The Dormouse's story]

    1. 属性查找
      查找时还可以加入属性元素,属性需要用中括号括起来,注意属性和标签属于同一节点,所以中间不能加空格,否则会无法匹配到。
    print soup.select('a[class="sister"]')
    #[<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>]
    
    print soup.select('a[href="http://example.com/elsie"]')
    #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]
    

    同样,属性仍然可以与上述查找方式组合,不在同一节点的空格隔开,同一节点的不加空格

    print soup.select('p a[href="http://example.com/elsie"]')
    #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]
    

    以上的 select 方法返回的结果都是列表形式,可以遍历形式输出,然后用 get_text() 方法来获取它的内容。

    soup = BeautifulSoup(html, 'lxml')
    print type(soup.select('title'))
    print soup.select('title')[0].get_text()
    
    for title in soup.select('title'):
        print title.get_text()
    
  • 相关阅读:
    composer使用git作为仓储
    monolog记录日志
    lumen laravel response对象返回数据
    lumen中间件 Middleware
    AcWing 901. 滑雪
    leetcode 34. 在排序数组中查找元素的第一个和最后一个位置
    acwing 902. 最短编辑距离
    ACWING 844. 走迷宫
    leetcode 5199. 交换字符串中的元素
    AcWing 836. 合并集合
  • 原文地址:https://www.cnblogs.com/cdinc/p/9266191.html
Copyright © 2020-2023  润新知