python爬虫Beautiful Soup基础知识总结(附带实操案例)

python爬虫之Beautiful Soup基础知识

Beautiful Soup是一个可以从HTML或XML文件中提取数据的python库。它能同过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。

需要注意的是,Beautiful Soup已经自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。因此在使用它的时候不需要考虑编码方式,仅仅需要说明一下原始编码方式就可以了。

一、安装Beautiful Soup库

使用pip命令工具安装Beautiful Soup4库

pip install beautifulsoup4

二、BeautifulSoup库的主要解析器

image.png

具体操作:

html = 'https://www.baidu.com'
bs = BeautifulSoup(html, 'html.parser')

三、BeautifulSoup的简单使用

提取百度搜索页面的部分源代码为例:

<!DOCTYPE html>
<html>
<head>
  <meta content="text/html;charset=utf-8" http-equiv="content-type" />
  <meta content="IE=Edge" http-equiv="X-UA-Compatible" />
  <meta content="always" name="referrer" />
  <link
href="https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.
css" rel="stylesheet" type="text/css" />
  <title>百度一下,你就知道 </title>
</head>
<body link="#0000cc">
 <div id="wrapper">
  <div id="head">
    <div class="head_wrapper">
     <div id="u1">
      <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="bri" href="//www.baidu.com/more/" name="tj_briicon"
style="display: block;">更多产品 </a>
     </div>
    </div>
  </div>
 </div>
</body>
</html>

综合requests和使用BeautifulSoup库的html解析器,对其进行解析如下:

import requests
from bs4 import BeautifulSoup

# 使用requests库加载页面代码
r = requests.get('https://www.baidu.com')
r.encoding = r.apparent_encoding
html = r.text

bs = BeautifulSoup(html, 'html.parser')

print(bs.prettify())    # prettify 方式输出页面

结果如下:

<!DOCTYPE html>
<!--STATUS OK-->
<html>
 <head>
  <meta content="text/html;charset=utf-8" http-equiv="content-type"/>
  <meta content="IE=Edge" http-equiv="X-UA-Compatible"/>
  <meta content="always" name="referrer"/>
  <link href="https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css" rel="stylesheet" type="text/css"/>
  <title>
   百度一下,你就知道
  </title>
 </head>
 <body link="#0000cc">
  <div id="wrapper">
   <div id="head">
    <div class="head_wrapper">
     <div class="s_form">
      <div class="s_form_wrapper">
       <div id="lg">
        <img height="129" hidefocus="true" src="//www.baidu.com/img/bd_logo1.png" width="270"/>
       </div>
       <form action="//www.baidu.com/s" class="fm" id="form" name="f">
        <input name="bdorz_come" type="hidden" value="1"/>
        <input name="ie" type="hidden" value="utf-8"/>
        <input name="f" type="hidden" value="8"/>
        <input name="rsv_bp" type="hidden" value="1"/>
        <input name="rsv_idx" type="hidden" value="1"/>
        <input name="tn" type="hidden" value="baidu"/>
        <span class="bg s_ipt_wr">
         <input autocomplete="off" autofocus="autofocus" class="s_ipt" id="kw" maxlength="255" name="wd" value=""/>
        </span>
        <span class="bg s_btn_wr">
         <input autofocus="" class="bg s_btn" id="su" type="submit" value="百度一下"/>
        </span>
       </form>
      </div>
     </div>
     <div id="u1">
      <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>
      <noscript>
       <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>
      </noscript>
      <script>
       document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');
      </script>
      <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">
       更多产品
      </a>
     </div>
    </div>
   </div>
   <div id="ftCon">
    <div id="ftConw">
     <p id="lh">
      <a href="http://home.baidu.com">
       关于百度
      </a>
      <a href="http://ir.baidu.com">
       About Baidu
      </a>
     </p>
     <p id="cp">
      ©2017 Baidu
      <a href="http://www.baidu.com/duty/">
       使用百度前必读
      </a>
      <a class="cp-feedback" href="http://jianyi.baidu.com/">
       意见反馈
      </a>
      京ICP证030173号
      <img src="//www.baidu.com/img/gs.gif"/>
     </p>
    </div>
   </div>
  </div>
 </body>
</html>

四、BeautifulSoup类的基本元素

BeautifulSoup将复制的HTML文档转换成一个复杂的树型结构,每个节点都是python对象,所有对象可以归纳为四种 Tag,NavigableString,Comment,Beautifulsoup 。

image.png

Tag

任何存在于HTML语法中的标签都可以bs.tag访问获得,如果在HTML文档中存在多个相同的tag对应的内容时,bs.tag返回第一个。示例代码如下:

import requests
from bs4 import BeautifulSoup

# 使用requests库加载页面代码
r = requests.get('https://www.baidu.com')
r.encoding = r.apparent_encoding
html = r.text
bs = BeautifulSoup(html, 'html.parser')
# 获取第一个a标签的所有内容
print(bs.a) # <a class="mnav" href="http://news.baidu.com" name="tj_trnews">新闻</a>
print(type(bs.a))   # <class 'bs4.element.Tag'>

在Tag标签中最重要的就是html页面中的nam和attrs属性,使用方法如下:

print(bs.a.name)    # a
# 把a标签的所有属性打印输出出来,返回一个字典类型
print(bs.a.attrs)   # {'href': 'http://news.baidu.com', 'name': 'tj_trnews', 'class': ['mnav']}
# 等价 bs.a.get('class')
print(bs.a['class'])    # ['mnav']
bs.a['class'] = 'newClass'  # 对class属性的值进行修改
print(bs.a) # <a class="newClass" href="http://news.baidu.com" name="tj_trnews">新闻</a>
del bs.a['class']   # 删除class属性
print(bs.a) # <a href="http://news.baidu.com" name="tj_trnews">新闻</a>

NavigableString

NavigableString中的string方法用于获取标签内部的文字,代码如下:

import requests
from bs4 import BeautifulSoup

# 使用requests库加载页面代码
r = requests.get('https://www.baidu.com')
r.encoding = r.apparent_encoding
html = r.text
bs = BeautifulSoup(html, 'html.parser')

print(bs.title.string)  # 百度一下,你就知道
print(type(bs.title.string))    # <class 'bs4.element.NavigableString'>

Comment

Comment对象是一个特殊类型的NavigableString对象,其输出的内容不包括注释符号,用于输出注释的内容。

from bs4 import BeautifulSoup

html = """<a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!--新闻--></a>"""
bs = BeautifulSoup(html, 'html.parser')

print(bs.a.string)  # 新闻
print(type(bs.a.string))    # <class 'bs4.element.Comment'>

BeautifulSoup

bs对象表示的是一个文档的全部内容,大部分时候,可以把它当作Tag对象,支持遍历文档树和搜索文档中描述的大部分方法。

因为Beautifulsoup对象并不是真正的HTML或者XML的tag,所以它没有name和attribute属性。所以BeautifulSoup对象一般包含值为"[document]"的特殊属性.name

print(bs.name)  # [document]

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

在HTML中有如下特定的基本格式,也是构成HTML页面的基本组成成分。

image.png

而在这种基本的格式下有三种基本的遍历流程

  • 下行遍历
  • 上行遍历
  • 平行遍历

三种遍历方式分别是从当前节点出发,对之上、之下、平行的格式以及关系进行遍历。

下行遍历

下行遍历分别有三种遍历属性,如下所示:

image.png

代码如下:

import requests
from bs4 import BeautifulSoup

# 使用requests库加载页面代码
r = requests.get('https://www.baidu.com')
r.encoding = r.apparent_encoding
html = r.text
bs = BeautifulSoup(html, 'html.parser')

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

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

# 输出子节点,以列表的形式
print(bs.head.contents)
print(bs.head.contents[0])  # 用列表索引来获取它的某一个元素

上行遍历

上行遍历有两种方式,如下所示:

image.png

代码如下:

import requests
from bs4 import BeautifulSoup

# 使用requests库加载页面代码
r = requests.get('https://www.baidu.com')
r.encoding = r.apparent_encoding
html = r.text
bs = BeautifulSoup(html, 'html.parser')

for parent in bs.a.parents:
    if parent is not None:
        print(parent.name)

print(bs.a.parent.name)

平行遍历

平行遍历有四种属性,如下所示:

image.png
image.png

代码如下:

import requests
from bs4 import BeautifulSoup

# 使用requests库加载页面代码
r = requests.get('https://www.baidu.com')
r.encoding = r.apparent_encoding
html = r.text
bs = BeautifulSoup(html, 'html.parser')

for sibling in bs.a.next_siblings:
    print(sibling)

for sibling in bs.a.previous_siblings:
    print(sibling)

其它遍历

image.png

六、文件树搜索

使用bs.find_all(name, attires, recursive, string, **kwargs)方法,用于返回一个列表类型,存储查找的结果。

image.png

name参数

如果是 指定的字符串 :会查找与字符串完全匹配的内容,代码如下:

a_list = bs.find_all("a")
print(a_list)

使用正则表达式:将会使用BeautifulSoup4中的search()方法来匹配,代码如下:

import requests
from bs4 import BeautifulSoup
import re

# 使用requests库加载页面代码
r = requests.get('https://www.baidu.com')
r.encoding = r.apparent_encoding
html = r.text
bs = BeautifulSoup(html, 'html.parser')

t_list = bs.find_all(re.compile("p"))
for item in t_list:
    print(item)

传入一个列表:Beautifulsoup4将会与列表中的任一元素匹配到的节点返回,代码如下:

import requests
from bs4 import BeautifulSoup

# 使用requests库加载页面代码
r = requests.get('https://www.baidu.com')
r.encoding = r.apparent_encoding
html = r.text
bs = BeautifulSoup(html, 'html.parser')

t_list = bs.find_all(["meta", "link"])
for item in t_list:
    print(item)

传入一个函数或方法:将会根据函数或者方法来匹配,代码如下:

import requests
from bs4 import BeautifulSoup

# 使用requests库加载页面代码
r = requests.get('https://www.baidu.com')
r.encoding = r.apparent_encoding
html = r.text
bs = BeautifulSoup(html, 'html.parser')


def name_is_exists(tag):
    return tag.has_attr("name")


t_list = bs.find_all(name_is_exists)
for item in t_list:
    print(item)

attrs参数

并不是所有的属性都可以使用上面这种方法进行搜索,比如HTML的data属性,用于指定属性搜索。

import requests
from bs4 import BeautifulSoup

# 使用requests库加载页面代码
r = requests.get('https://www.baidu.com')
r.encoding = r.apparent_encoding
html = r.text
bs = BeautifulSoup(html, 'html.parser')

t_list = bs.find_all(attrs={"class": "mnav"})


for item in t_list:
    print(item)

string参数

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

import requests
from bs4 import BeautifulSoup
import re

# 使用requests库加载页面代码
r = requests.get('https://www.baidu.com')
r.encoding = r.apparent_encoding
html = r.text
bs = BeautifulSoup(html, 'html.parser')

t_list = bs.find_all(attrs={"class": "mnav"})
for item in t_list:
    print(item)

# text用于搜索字符串
t_list = bs.find_all(text="hao123")
for item in t_list:
    print(item)

# text可以通其它参数混合使用用来过滤tag
t_list = bs.find_all("a", text=["hao123", "地图", "贴吧"])
for item in t_list:
    print(item)

t_list = bs.find_all(text=re.compile("\d\d"))
for item in t_list:
    print(item)

使用find_all()方法,常用到的正则表达式形式 import re 代码如下:

bs.find_all(string = re.compile('python'))  # 指定查找内容

# 或者指定使用正则表达式要搜索的内容
string = re.compile('python')   # 字符为python
bs.find_all(string) # 调用方法模版

七、常用的find()方法如下

image.png

八、爬取京东电脑数据

爬取的例子直接输出到屏幕。

(1)要爬取京东一页的电脑商品信息,下图所示:

image.png

(2)我们的目的是需要获取京东这一个页面上所有的电脑数据,包括价格,名称,ID等。具体代码如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import requests
from bs4 import BeautifulSoup

headers = {
        'User-agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) "
                      "Chrome/66.0.3359.139 Safari/537.36"
    }

URL = "https://search.jd.com/search?keyword=macbook%20pro&qrst=1&suggest=5.def.0.V09&wq=macbook%20pro"

r = requests.get(URL, headers=headers)
r.encoding = r.apparent_encoding
html = r.text
bs = BeautifulSoup(html, 'html.parser')

all_items = bs.find_all('li', attrs={"class": "gl-item"})

for item in all_items:
    computer_id = item["data-sku"]
    computer_name = item.find('div', attrs={'class': 'p-name p-name-type-2'})
    computer_price = item.find('div', attrs={'class': 'p-price'})
    print('电脑ID为:' + computer_id)
    print('电脑名称为:' + computer_name.em.text)
    print('电脑价格为:' + computer_price.find('i').string)
    print('------------------------------------------------------------')

部分结果如下图所示:

image.png
555.png

来源:本文位第三方转载,如有侵权请联系小编删除。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,423评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,339评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,241评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,503评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,824评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,262评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,615评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,337评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,989评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,300评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,829评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,193评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,753评论 3 230
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,970评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,708评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,295评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,207评论 2 258