爬虫笔记3-信息标记提取

2018-12-27  本文已影响0人  三流之路

信息标记和提取

信息标记的三种形式

  1. XML

    最早的通用信息标记语言,可扩展性好,但繁琐。

    主要用于 Internet 上的信息交互与传递。

  2. JSON

    信息有类型,适合程序处理(js),较 XML 简洁。

    主要用于移动应用云端和节点的信息通信,缺点是无注释

  3. YAML

    信息无类型,文本信息比例最高,如 name:silas,没有引号标明是字符串。

    主要用于各类系统的配置文件,有注释易读。

    1. 缩进表达所属关系

      name:
          newName: mzj
          oldName: myz
      
    2. - 表达并列关系

      name:
      - mzj
      - myz
      
    3. | 表达整块数据,# 表示注释

      text: | # 介绍
      abcdefghijklmnopqrstuvwxyz0123456789
      

信息提取

soup = BeautifulSoup(res.text, 'html.parser')
# 搜索所有 <a> 标签内容
for link in soup.find_all('a'):
    print(link.get('href'))
find_all(name, attrs, recursive, string, **kwargs)

返回一个列表类型,存储查找的结果

  1. name:对标签名称的检索字符串

    # 提取一个标签
    soup.find_all('a')
    # 提取多个标签
    soup.find_all(['a','div'])
    
    # 参数为 True 提取所有标签
    for tag in soup.find_all(True):
        print(tag.name)
        
    # 提取所有匹配正则表达式(以 b 开头)的标签
    import re
    for tag in soup.find_all(re.compile('b')):
        print(tag.name)
    
  2. attrs:对标签属性值的检索字符串,可标注属性检索

    所有 <a> 标签中有 bri 属性的标签。

    >>> soup.find_all('a', 'bri')
    [<a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品</a>]
    

    所有 id 为 lh 的标签

    >>> soup.find_all(id="lh")
    [<p id="lh"> <a href="http://home.baidu.com">关于百度</a> <a href="http://ir.baidu.com">About Baidu</a> </p>]
    

    所有包含 link 文字的 id,比如 link1alinkb

    >>> soup.find_all(id=re.compile('link'))
    []
    
  3. recursive:是否对子孙全部检索,默认True

    >>> soup.find_all('a')
    

    [<a class="mnav" href="http://news.baidu.com" name="tj_trnews">新闻</a>, <a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123</a>, <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图</a>, <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频</a>, <a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧</a>, <a class="lb" href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1" name="tj_login">登录</a>, <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品</a>, <a href="http://home.baidu.com">关于百度</a>, <a href="http://ir.baidu.com">About Baidu</a>, <a href="http://www.baidu.com/duty/">使用百度前必读</a>, <a class="cp-feedback" href="http://jianyi.baidu.com/">意见反馈</a>]

    >>> soup.find_all('a',recursive=False)
    

    什么都没有,输出 []

  4. string: 对标签中字符串区域的检索字符串

    文档中有 "> <a href="http://home.baidu.com">关于百度</a> <a href="http://ir.baidu.com">About Baidu</a> 这么一条

    >>> soup.find_all(string="关于百度")
    ['关于百度']
    

    所有含有“百度”的内容

    >>> soup.find_all(string=re.compile('百度'))
    ['百度一下,你就知道', '关于百度', '使用百度前必读']
    

简写:

<tag>() 等价 <tag>.find_all()
soup() 等价 soup.find_all()

扩展方法

方法 说明
<>.find() 搜索且只返回一个结果, 同 .find_all() 参数
<>.find_parents() 在先辈节点中搜索,返回列表类型,同 .find_all() 参数
<>.find_parent() 在先辈节点中返回一个结果,同 .find() 参数
<>.find_next_siblings() 在后续平行节点中搜索,返回列表类型,同 .find_all() 参数
<>.find_next_sibling() 在后续平行节点中返回一个结果,同 .find() 参数
<>.find_previous_siblings() 在前序平行节点中搜索,返回列表类型,同 .find_all() 参数
<>.find_previous_sibling() 在前序平行节点中返回一个结果,同 .find() 参数

实例

爬取 http://www.zuihaodaxue.cn/zuihaodaxuepaiming2018.html 的大学排名并提取信息。

思考步骤:

  1. 打开网页,查看源代码,查找一个大学,比如“清华大学”,定位到代码位置

    university.png

    一个 <tr> 包含一个大学,具体信息在 <td> 标签中,前四个分别为大学排名,大学名称,所在城市,分数。

  2. 打开 http://www.zuihaodaxue.cn/robots.txt 看网站是否禁止爬取,结果是没有这个文件,所以可以爬取

  3. 定义输出结果,按排名、学校名称、总分排列

  4. 定义方法 getHTMLText() 爬取网页内容

  5. 定义方法 fillUnivList() 将网页内容提取到合适的数据结构中

  6. 定义方法 printUnivList() 将数据结构中内容输出显示

import requests
import bs4

def getHTMLText(url):
    try:
        res = requests.get(url, timeout=30)
        res.raise_for_status()
        res.encoding = res.apparent_encoding
        return res.text
    except:
        return ""

def fillUnivList(ulist, html):
    soup = bs4.BeautifulSoup(html, 'html.parser')
    for tr in soup.find('tbody').children: # 遍历子节点,每个 tr 就是一所大学
        if isinstance(tr, bs4.element.Tag): # 过滤掉不是标签类型的子节点
            tds = tr('td') # 相当于 tr.find_all('td') 找 tr 里面的所有 td
            ulist.append([tds[0].string, tds[1].string, tds[3].string])

def printUnivList(ulist, num):
    tplt = "{0:^10}\t{1:{3}^10}\t{2:^10}"
    print(tplt.format("排名","学校名称","总分",chr(12288)))
    for i in range(num):
        u = ulist[i]
        print(tplt.format(u[0],u[1],u[2],chr(12288)))

def main():
    uinfo = [] # 存储大学信息的列表
    url = 'http://www.zuihaodaxue.cn/zuihaodaxuepaiming2018.html'
    html = getHTMLText(url)
    fillUnivList(uinfo, html)
    printUnivList(uinfo, 20) # 只打印前 20 名大学数据

main()
上一篇下一篇

猜你喜欢

热点阅读