Python爬虫实战一之使用Beautiful Soup抓取‘谣言百科’的分类内容

Beautiful Soup功能介绍

简介

   Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.

   Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时,Beautiful Soup就不能自动识别编码方式了。

支持的解析器

Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是lxml .根据操作系统不同,可以选择下列方法来安装lxml

解析器

  使用方法 优势 劣势
Python标准库 BeautifulSoup(markup,"html.parser")
  • Python的内置标准库
  • 执行速度适中
  • 文档容错能力强
  • Python 2.7.3 or 3.2.2)前的版本中文档容错能力差
lxml HTML 解析器 BeautifulSoup(markup,"lxml")
  • 速度快
  • 文档容错能力强
  • 需要安装C语言库
lxml XML 解析器

BeautifulSoup(markup,["lxml-xml"])

BeautifulSoup(markup,"xml")

  • 速度快
  • 唯一支持XML的解析器
  • 需要安装C语言库
html5lib BeautifulSoup(markup,"html5lib")
  • 最好的容错性
  • 以浏览器的方式解析文档
  • 生成HTML5格式的文档
  • 速度慢
  • 不依赖外部扩

使用简单案例

from bs4 import BeautifulSoup
soup = BeautifulSoup(open("index.html"))
soup = BeautifulSoup("data")
print BeautifulSoup("Hello World!")
执行结果:

Hello World!


解析的对象种类

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

<1>Tag

Tag 对象与XML或HTML原生文档中的tag相同,

soup = BeautifulSoup('Extremely bold')
tag = soup.b
type(tag)
# 
(1)tag中最重要的属性: name和attributes

每个tag都有自己的名字,通过.name 来获取,一个tag可能有很多个属性. tagclass="boldest"> 有一个 “class” 的属性,值为 “boldest” . tag的属性的操作方法与字典相同,如下

getsoup=BeautifulSoup("

Hello World!

") tag=getsoup.p print tag print tag.name print tag['class'] ----结果----

Hello World!

body ['test']
(2) 可以遍历的字符串

字符串常被包含在tag内.Beautiful Soup用NavigableString 类来包装tag中的字符串:

print tag.string-----------Hello World!

(3)注释及特殊字符串

Tag ,NavigableString ,BeautifulSoup 几乎覆盖了html和xml中的所有内容,但是还有一些特殊对象.容易让人担心的内容是文档的注释部分:

markup = ""
soup = BeautifulSoup(markup)
comment = soup.b.string
print type(comment)
print comment

Hey, buddy. Want to buy a used parser?

(4)遍历文档树

子节点
一个Tag可能包含多个字符串或其它的Tag,这些都是这个Tag的子节点.Beautiful Soup提供了许多操作和遍历子节点的属性.
注意: Beautiful Soup中字符串节点不支持这些属性,因为字符串没有子节点

循环遍历:

如果想要得到所有的标签,或是通过名字得到比一个tag更多的内容的时候,就需要用到Searching the tree 中描述的方法,比如: find_all()

print soup.find_all('a')

1).contents 和 .children

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

通过tag的 .children 生成器,可以对tag的子节点进行循环

2).descendants 属性可以对所有tag的子孙节点进行递归循环 [5]

3).strings 和 stripped_strings

如果tag中包含多个字符串 [2] ,可以使用 .strings 来循环获取:
输出的字符串中可能包含了很多空格或空行,使用 .stripped_strings 可以去除多余空白内容

父节点

1).parent
通过 .parent 属性来获取某个元素的父节点.在例子“爱丽丝”的文档中,标签是标签的父节点</span></p> <p><span style="font-family:'KaiTi_GB2312';">2).parents<br> 通过元素的 .parents 属性可以递归得到元素的所有父辈节点,下面的例子使用了 .parents 方法遍历了<a>标签到根节点的所有节点.</span></p> <p><span style="font-family:'KaiTi_GB2312';"><strong>兄弟节点</strong><br></span></p> <p><span style="font-family:'KaiTi_GB2312';">1).next_sibling 和 .previous_sibling<br> 在文档树中,使用 .next_sibling 和 .previous_sibling 属性来查询兄弟节点<br> 2).next_siblings 和 .previous_siblings<br> 通过 .next_siblings 和 .previous_siblings 属性可以对当前节点的兄弟节点迭代输出<br></span></p> <p><span style="font-family:'KaiTi_GB2312';"><strong>回退或前进</strong></span></p> <p><span style="font-family:'KaiTi_GB2312';">1).next_element 和 .previous_element<br> .next_element 属性指向解析过程中下一个被解析的对象(字符串或tag),结果可能与 .next_sibling 相同,但通常是不一样的.<br> 2).next_elements 和 .previous_elements<br> 通过 .next_elements 和 .previous_elements 的迭代器就可以向前或向后访问文档的解析内容,就好像文档正在被解析一样:<br></span></p> <p><span style="font-family:'KaiTi_GB2312';"><strong>(5)搜索文档树</strong></span></p> <p><span style="font-family:'KaiTi_GB2312';"><strong>过滤器----find_all()</strong><br></span></p> <p><span style="font-family:'KaiTi_GB2312';">1)字符串<br> 最简单的过滤器是字符串.在搜索方法中传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容,下面的例子用于查找文档中所有的<b>标签:</span></p> <p><span style="font-family:'KaiTi_GB2312';">soup.find_all('b') <br> 2)正则表达式<br> 如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的 match() 来匹配内容.下面例子中找出所有以b开头的标签,这表示<body>和<b>标签都应该被找到<br> import re<br> for tag in soup.find_all(re.compile("^b")):<br>     print(tag.name)</span></p> <p><span style="font-family:'KaiTi_GB2312';">3)列表<br> 如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回.下面代码找到文档中所有<a>标签和<b>标签:<br> soup.find_all(["a", "b"])</span></p> <p><span style="font-family:'KaiTi_GB2312';">4)True<br> True 可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点<br> for tag in soup.find_all(True):<br>     print(tag.name)</span></p> <p><span style="font-family:'KaiTi_GB2312';">5)方法<br> 如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 [4] ,如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 False<br> 下面方法校验了当前元素,如果包含 class 属性却不包含 id 属性,那么将返回 True:<br> def has_class_but_no_id(tag):<br>     return tag.has_attr('class') and not tag.has_attr('id')<br> 将这个方法作为参数传入 find_all() 方法,将得到所有<p>标签:<br> soup.find_all(has_class_but_no_id)<br> # [<p class="title"><b>The Dormouse's story</b></p>,<br> #  <p class="story">Once upon a time there were...</p>,<br> #  <p class="story">...</p>]</span></p> <p><span style="font-family:'KaiTi_GB2312';">6)name 参数<br> name 参数可以查找所有名字为 name 的tag,字符串对象会被自动忽略掉.<br> 简单的用法如下:<br> soup.find_all("title")<br> # [<title>The Dormouse's story]
重申: 搜索 name 参数的值可以使任一类型的 过滤器 ,字符窜,正则表达式,列表,方法或是 True .
keyword 参数
如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索,如果包含一个名字为 id 的参数,Beautiful Soup会搜索每个tag的”id”属性.
soup.find_all(id='link2')
# [
Lacie]
如果传入 href 参数,Beautiful Soup会搜索每个tag的”href”属性:
soup.find_all(href=re.compile("elsie"))
# [Elsie]
搜索指定名字的属性时可以使用的参数值包括 字符串 , 正则表达式 , 列表, True .

其它详见:http://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/

Beautiful Soup抓取‘谣言百科’的分类内容

源代码:

# -*- coding:UTF-8 -*-
# 2017年7月15日
# 爬虫目标网站:http://www.yaoyanbaike.com/
# 获取信息BeautifulSoup+request
import urllib2
from bs4 import BeautifulSoup
import re
import codecs

if __name__ == "__main__":
    text_file_number = 0    # 同一类新闻下的索引数
    number = 1  # 同类别新闻不同页面下的索引数
    while (number <= 2):
        if number==1:   # 第一个新闻下地址是baby不是baby_数字所以要区分判断一下
            get_url = 'http://www.yaoyanbaike.com/category/baby.html'
        else:
            get_url = 'http://www.yaoyanbaike.com/category/baby_'+str(number)+'.html'   #这个是baby_数字,number就是目录索引数
        head = {}   #设置头
        head['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0'
        # 模拟浏览器模式,定制请求头
        download_req_get = urllib2.Request(url = get_url, headers = head)
        # 设置Request
        download_response_get = urllib2.urlopen(download_req_get)
        # 设置urlopen获取页面所有内容
        download_html_get = download_response_get.read().decode('UTF-8','ignore')
        # UTF-8模式读取获取的页面信息标签和内容
        soup_texts = BeautifulSoup(download_html_get, 'lxml')
        # BeautifulSoup读取页面html标签和内容的信息        
        for link  in soup_texts.find_all(["a"]):
            print(str(text_file_number)+"   "+str(number)+"    "+str(link.get('title')))
            # 打印文件地址用于测试
            s=link.get('href')
            if s.find("/a/") == -1:
                print("错误网址")   # 只有包含"/a/"字符的才是有新闻的有效地址
            else:
                download_url = link.get('href')
                head = {}
                head['User-Agent'] = 'Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166  Safari/535.19'
                download_req = urllib2.Request(url = "http://www.yaoyanbaike.com"+download_url, headers = head)
                download_response = urllib2.urlopen(download_req)
                download_html = download_response.read().decode('UTF-8','ignore')
                soup_texts = BeautifulSoup(download_html, 'lxml')
                texts = soup_texts.find_all('article')
                soup_text = BeautifulSoup(str(texts), 'lxml')
                p = re.compile("<[^>]+>")  
                text=p.sub("", str(soup_text))
                # 去除页面标签
                f1 = codecs.open('E:\pic\\'+str(text_file_number)+'--'+str(link.get('title')).decode('utf-8')+'.txt','w','UTF-8')
#                 f1 = codecs.open('E:\pic\\'+str(text_file_number)+'.txt','w','UTF-8')
                # 排序id+按标题名称将信息存储在本地
                f1.write(text)
                f1.close()
                text_file_number = text_file_number + 1
        number = number + 1

执行结果:

Python爬虫实战一之使用Beautiful Soup抓取‘谣言百科’的分类内容_第1张图片

你可能感兴趣的:(python学习篇,python,网络爬虫)