python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)

Beautiful Soup库入门

1.Beautiful Soup 是一个HTML/XML 的解析器,主要用于解析和提取 HTML/XML 数据。
2.它基于HTML DOM 的,会载入整个文档,解析整个DOM树,因此时间和内存开销都会大很多,所以性能要低于lxml。
3. BeautifulSoup 用来解析 HTML 比较简单,API非常人性化,支持CSS选择器、Python标准库中的HTML解析器,也支持 lxml 的 XML解析器。
4.虽然说BeautifulSoup4 简单容易比较上手,但是匹配效率还是远远不如正则以及xpath的,一般不推荐使用,推荐正则的使用。

0 Beautiful Soup库的理解

Beautiful Soup库是解析、遍历、维护“标签树”的功能库,也叫beautifulsoup4 或 bs4。约定引用方式如下,即主要是用BeautifulSoup类。BeautifulSoup对应一个HTML/XML文档的全部内容。

from bs4 import BeautifulSoup # 导入
import bs4
soup = BeautifulSoup('data', 'html.parser' ) # 创建Beautiful Soup对象

bs4库将任何读入的HTML文件或字符串都转换成为’utf-8’编码(国际通用的标准编码格式,能够很好的支持中文等第三国语言),由于python3系列默认支持编码是’utf-8’,因此在做相关解析时使用bs库没有任何障碍。若用的python2解析器,则要无穷无尽的做相应的转换。

# bs4库编码的小例子
soup = BeautifulSoup("

中文

"
,"html.parser") soup.p.string

在这里插入图片描述

print(soup.p.prettify())

在这里插入图片描述
python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第1张图片

1 Beautiful Soup库解析器

soup = BeautifulSoup(‘data’, ‘html.parser’)

解析器 使用方法 条件 特点
bs4 HTML解析器 BeautifulSoup(mk,‘html.parser’) 安装bs4库 Python的内置标准库,执行速度适中,文档容错能力强
lxml HTML解析器 BeautifulSoup(mk,‘lxml’) pip install lxml 速度快,文档容错能力强
lxml XML解析器 BeautifulSoup(mk,‘xml’) pip install lxml 速度快,唯一支持XML的解析器
html5lib解析器 BeautifulSoup(mk,‘html5lib’) pip install html5lib 最好的容错性,以浏览器的方式解析文档,生成HTML5格式的文档,速度慢

2 Beautiful Soup库的基本元素

Beautiful Soup将复杂HTNL文档转换成一个复杂的树形结构,每个节点都是python对象,所有对象可以分为以下5种:

  • Tag:标签,最基本的信息组织单元,分别用<>和标明开头和结尾
  • Name:标签的名字,

    的名字是’p’,格式:.name

  • Attributes:标签的属性,字典形式组织,格式:.attrs
  • NavigableString:标签内非属性字符串,<>…中字符串,格式:.string
  • Comment:标签内字符串的注释部分,一种特殊的Comment类型
# 导入bs4库
from bs4 import BeautifulSoup
import requests 

r = requests.get('https://python123.io/ws/demo.html') # 抓取页面(Demo网址)
demo = r.text  # 抓取的数据(网页源码)
demo

python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第2张图片

# 解析HTML页面
soup = BeautifulSoup(demo, 'html.parser')  # bs4的解析器,解析页面数据(网页源码)
# 有层次感的输出解析后的HTML页面
print(soup.prettify()) # prettify()为HTML文本<>及其内容增加更加'\n',有层次感的输出
# prettify()可用于标签,方法:.prettify()

python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第3张图片
1)Tag标签,用soup.访问获得:

  • 任何存在于HTML语法中的标签都可以用soup.访问获得
  • 当HTML文档中存在多个相同soup.对应内容时,soup.返回第一个
soup.a # 访问标签a
>> <a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>

soup.title # 访问标签title
>> <title>This is a python demo page</title>

2)标签的name(名字):

  • 每个都有自己的名字,通过soup..name获取,字符串类型
soup.a.name
>> 'a'
soup.a.parent.name
>> 'p'
soup.p.parent.name
>> 'body'
  1. 标签的Attributes(属性):
  • 一个可以有0或多个属性,字典类型,soup..attrs
tag = soup.a
print(tag.attrs)  
print(tag.attrs['class'])
print(type(tag.attrs))
>> {'href': 'http://www.icourse163.org/course/BIT-268001', 'class': ['py1'], 'id': 'link1'}
>> ['py1']
>> <class 'dict'>
  1. 标签的NavigableString
  • 标签内非属性字符串,格式:soup..string, NavigableString可以跨越多个层次
print(soup.a.string)
print(type(soup.a.string))
>> Basic Python
>> <class 'bs4.element.NavigableString'>

5)标签的Comment

  • 标签内字符串的注释部分,Comment是一种特殊类型(有–>)
newsoup = BeautifulSoup("

This is not a comment

"
,"html.parser") newsoup.b.string >> 'This is a comment' type(newsoup.b.string) >> bs4.element.Comment newsoup.p.string >> 'This is not a comment' type(newsoup.p.string) >> bs4.element.NavigableString

3 基于bs4库的HTML内容遍历方法

HTML基本格式:<>…构成了所属关系,形成了标签的树形结构

1)标签树的下行遍历

属性 说明
.contents 子节点的列表,将所有儿子节点存
.children 子节点的迭代类型,与.contents类似,用于循环遍历儿子节点
.descendants 子孙节点的迭代类型,包含所有子孙节点,用于循环遍历
import requests
from bs4 import BeautifulSoup

r=requests.get('http://python123.io/ws/demo.html')
demo=r.text
soup=BeautifulSoup(demo,'html.parser')
print(soup.prettify())

python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第4张图片

print(soup.contents)# 获取整个标签树的儿子节点

python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第5张图片

print(soup.body.content)#返回标签树的body标签下的节点

在这里插入图片描述

print(soup.head)#返回head标签

在这里插入图片描述

print(soup.head.contents)#返回head标签的儿子节点

在这里插入图片描述

for child in soup.body.children:#遍历儿子节点
    print(child)

python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第6张图片

for child in soup.body.descendants:#遍历子孙节点
    print(child)

python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第7张图片
2)标签树的上行遍历

属性 说明
.parent 节点的父亲标签
.parents 节点先辈标签的迭代类型,用于循环遍历先辈节点
soup.title.parent

在这里插入图片描述

soup.html.parent

python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第8张图片

for parent in soup.a.parents: # 遍历所有先辈节点,包括soup本身,所以要区别判断
    if parent is None:
        print(parent)
    else:
        print(parent.name)

在这里插入图片描述
3)标签树的平行遍历

属性 说明
.next_sibling 返回按照HTML文本顺序的下一个平行节点标签
.previous_sibling 返回按照HTML文本顺序的上一个平行节点标签
.next_siblings 迭代类型,返回按照HTML文本顺序的后续所有平行节点标签
.previous_siblings 迭代类型,返回按照HTML文本顺序的前续所有平行节点标签

python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第9张图片

print(soup.a.next_sibling)#a标签的下一个标签

在这里插入图片描述

print(soup.a.next_sibling.next_sibling)#a标签的下一个标签的下一个标签

在这里插入图片描述

print(soup.a.previous_sibling)#a标签的前一个标签

在这里插入图片描述

print(soup.a.previous_sibling.previous_sibling)#a标签的前一个标签的前一个标签

在这里插入图片描述

for sibling in soup.a.next_siblings:#遍历后续节点
    print(sibling)

在这里插入图片描述

4 基于bs4库的HTML内容的查找方法

python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第10张图片
python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第11张图片
python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第12张图片

# name : 对标签名称的检索字符串
soup.find_all('a')

在这里插入图片描述

soup.find_all(['a', 'p'])

python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第13张图片

# attrs: 对标签属性值的检索字符串,可标注属性检索
soup.find_all("p","course")

python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第14张图片

soup.find_all(id="link") # 完全匹配才能匹配到
>> []

#  recursive: 是否对子孙全部检索,默认True
soup.find_all('p',recursive=False)
>> []

# string: <>…中字符串区域的检索字符串
soup.find_all(string = "Basic Python") # 完全匹配才能匹配到
>> ['Basic Python']

5 实战:中国大学排名定向爬取

  • 采用requests-bs4路线实现了中国大学排名定向爬虫

  • 对中英文混排输出问题进行了优化

  • 爬取url:http://www.zuihaodaxue.cn/zuihaodaxuepaiming2019.html

  • 爬取思路:
    1.从网络上获取大学排名网页内容
    2.提取网页内容中信息到合适的数据结构(二维数组)-排名,学校名称,总分
    3.利用数据结构展示并输出结果

if isinstance(tr,bs4.element.Tag):

1.isinstance:判断一个对象是否是一个已知的类型,类似于type()

type()不考虑子类是父类的一种类型,不考虑继承关系
isinatance()认为子类是父类的一种类型,考虑继承关系

2.bs4.element.Tag

bs4是包,element是模块,Tag是类名
tag是‘bs4.element.Tag’的实例对象,或者说tag的数据类型是bs4.element.Tag
# 导入库
import requests
from bs4 import BeautifulSoup
import bs4

def getHTMLText(url):
    try:
        r = requests.get(url,timeout=30)  # 获取url信息,并且设置时间
        r.raise_for_status()  # 产生异常信息
        r.encoding=r.apparent_encoding  # 修改编码
        return r.text  # 将网页的信息内容返回给程序的其他部分
    except:
        return ""

def fillUnivList(ulist,html):# 提取HTML中关键的数据并且添加一个列表中
    soup = BeautifulSoup(html,"html.parser")
    for tr in soup.find("tbody").children: # 解析HTML代码中的tbody标签所在的位置,在tbody标签中找到每一所大学对应的tr标签
        if isinstance(tr,bs4.element.Tag): #检测tr标签的类型,如果类型不是bs4库定义的Tag类型则过滤掉
            tds=tr('td')  # 对tr标签中的td标签做查询,将所有的td标签存为一个列表类型tds
            ulist.append([tds[0].string,tds[1].string,tds[3].string])  #  在ulist中增加我们需要的对应字段(大学排名,大学名称,大学得分)

def printUnivList(ulist,num):
    tplt = "{0:^10}\t{1:{3}^10}\t{2:^10}"  # 生成一个输出模板的变量,主要增加中间的宽度设定,将变量的输出按照顺序来表示。
    # 把字符串宽度都定义为10,但是中文本身的宽度都不到10所以会填充西文空格(字符),就会导致字符的实际宽度长短不一,所以需要用chr(12288)增加中文空格的变量位置
    # 在1号位填充{3}的原因是:中英文全半角造成不对齐的原因产生在1号位;
    # {3}指的是我们需要对format函数的三个变量(排名,学校名称,总分)进行填充(也就是中文字符的空格填充)
    print(tplt.format("排名","学校名称","总分",chr(12288))) # 实现对表头的打印,用chr(12288)增加中文空格的变量位置
    for i in range(num):
        u=ulist[i] # 将第i个学校信息用一个简短的变量u来代替
        print(tplt.format(u[0],u[1],u[2],chr(12288))) # 将每一所学校信息打印出来。(注:为了保证输出效果,需要用跟表头相一致的字符串表示)
    
def main():
    uinfo=[]
    url='http://www.zuihaodaxue.com/zuihaodaxuepaiming2019.html'
    html=getHTMLText(url)
    fillUnivList(uinfo,html)
    printUnivList(uinfo,30) # 30 univs
    
main()

python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第15张图片

若输出再添加一个“省市”变量,则fillUnivList函数和printUnivList函数里面的内容应做相应的改变,如下所示:

def fillUnivList(ulist,html):
    soup = BeautifulSoup(html,"html.parser")
    for tr in soup.find("tbody").children: 
        if isinstance(tr,bs4.element.Tag): 
            tds=tr('td')  
            ulist.append([tds[0].string,tds[1].string,tds[3].string,tds[2].string]) 
            #  在ulist中增加我们需要的对应字段(大学排名,大学名称,总分,省份)

def printUnivList(ulist,num):
    tplt = "{0:^10}\t{1:{4}^10}\t{2:^10}\t{3:^10}"  
    # 添加了地区(省市),相应地作为填充不足10个字符长度的chr(12288)已经不是3了,而是4。所以,在1号位上应填充{4}
    print(tplt.format("排名","学校名称","总分","省市",chr(12288))) 
    for i in range(num):
        u=ulist[i] 
        print(tplt.format(u[0],u[1],u[2],u[3],chr(12288)))

python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第16张图片

关于Python format 输出的格式问题,总结如下:
python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取)_第17张图片

采用.format打印输出时,可以定义输出字符串的输出宽度,在 ‘:’ 后传入一个整数, 可以保证该域至少有这么多的宽度。 用于美化表格时很有用。

但是在打印多组中文的时候,不是每组中文的字符串宽度都一样,当中文字符宽度不够的时候,程序默认采用西文空格(字符)填充,中西文空格宽度不一样,就会导致输出文本不整齐。

所以,中文对齐问题的解决方法是:采用中文字符的空格填充chr(12288)

你可能感兴趣的:(python爬虫编程实践 Task2--Beautiful Soup库入门(实战:中国大学排名定向爬取))