整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

python 模块BeautifulSoup 从HT

python 模块BeautifulSoup 从HTML或XML文件中提取数据

、安装

Beautiful Soup 是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据。

lxml 只会局部遍历,而Beautiful Soup 是基于HTML DOM的,会载入整个文档,解析整个DOM树,因此时间和内存开销都会大很多,所以性能要低于lxml。

BeautifulSoup 用来解析 HTML 比较简单,API非常人性化,支持CSS选择器、Python标准库中的HTML解析器,也支持 lxml 的 XML解析器。

pip install beautifulsoup4

二、使用案例

from bs4 import BeautifulSoup
import requests
import asyncio
import functools
import re

house_info=[]

'''异步请求获取链家每页数据'''
async def get_page(page_index):
    headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36'
    }
    request=functools.partial(requests.get, f'https://sh.lianjia.com/ershoufang/pudong/pg{page_index}/',
                                headers=headers)
    loop=asyncio.get_running_loop()
    response=await loop.run_in_executor(None, request)
    return response


'''使用xpath获取房屋信息'''
def get_house_info(soup):
    house_info_list=soup.select('.info')  # 房屋title
    reg=re.compile(r'\n|\s')
    for html in house_info_list:

        house_info.append({
            'title': re.sub(reg,'',html.select('.title a')[0].getText()),
            'house_pattern': re.sub(reg,'',html.select('.houseInfo')[0].getText()),
            'price': re.sub(reg,'',html.select('.unitPrice')[0].getText()),
            'location': re.sub(reg,'',html.select('.positionInfo')[0].getText()),
            'total': re.sub(reg,'',html.select('.totalPrice')[0].getText())
        })

'''异步获取第一页数据,拿到第一页房屋信息,并返回分页总数和当前页'''
async def get_first_page():
    response=await get_page(1)
    soup=BeautifulSoup(response.text, 'lxml')
    get_house_info(soup)
    print(house_info)


if __name__=='__main__':
    asyncio.run(get_first_page())

三、创建soup对象

soup=BeautifulSoup(markup="", features=None, builder=None,parse_only=None, from_encoding=None, exclude_encodings=None,element_classes=None)

  • markup:要解析的HTML或XML文档字符串。可以是一个字符串变量,也可以是一个文件对象(需要指定"html.parser"或"lxml"等解析器)。
  • features:指定解析器的名称或类型。默认为"html.parser",可以使用其他解析器如"lxml"、"html5lib"等。
  • builder:指定文档树的构建器。默认为None,表示使用默认构建器。可以使用"lxml"或"html5lib"等指定其他构建器。
  • parse_only:指定要解析的特定部分。可以传递一个解析器或一个标签名或一个元素的列表。
  • from_encoding:指定解析器使用的字符编码。默认为None,表示自动检测编码。
  • exclude_encodings:指定要排除的编码列表,用于字符编码自动检测。
  • element_classes:指定要用于解析文档的元素类。默认为None,表示使用默认元素类。

解析器

使用方法

优势

劣势

Python标准库

BeautifulSoup(markup,"html.parser")

Python 的内置标准库、执行速度适中 、文档容错能力强

Python 2.7.3 or3.2.2) 前的版本中文容错能力差

LXML HTML 解析器

BeautifulSoup(markup,"lxml")

速度快、文档容错能力强

需要安装 C 语言库

LXML XML解析器

BeautifulSoup(markup,"xml")

速度快、唯一支持 XML 的解析器

需要安装 C 语言库

html5lib

BeautifulSoup(markup,"html5lib")

最好的容错性、以浏览器的方式解析文档、生成 HTML5 格式的文档

速度慢、不依赖外部扩展

四、soup对象

  1. soup.prettify(encoding=None, formatter="minimal"):返回格式化后的HTML或XML文档的字符串表示。它将文档内容缩进并使用适当的标签闭合格式,以提高可读性
  2. soup.title:返回文档的

析动态内容

根据权威机构发布的全球互联网可访问性审计报告,全球约有四分之三的网站其内容或部分内容是通过JavaScript动态生成的,这就意味着在浏览器窗口中“查看网页源代码”时无法在HTML代码中找到这些内容,也就是说我们之前用的抓取数据的方式无法正常运转了。解决这样的问题基本上有两种方案,一是JavaScript逆向工程;另一种是渲染JavaScript获得渲染后的内容。

JavaScript逆向工程

下面我们以“360图片”网站为例,说明什么是JavaScript逆向工程。其实所谓的JavaScript逆向工程就是找到通过Ajax技术动态获取数据的接口。

但是当我们在浏览器中通过右键菜单“显示网页源代码”的时候,居然惊奇的发现页面的HTML代码中连一个<img>标签都没有,那么我们看到的图片是怎么显示出来的呢?原来所有的图片都是通过JavaScript动态加载的,而在浏览器的“开发人员工具”的“网络”中可以找到获取这些图片数据的网络API接口,

那么结论就很简单了,只要我们找到了这些网络API接口,那么就能通过这些接口获取到数据,当然实际开发的时候可能还要对这些接口的参数以及接口返回的数据进行分析,了解每个参数的意义以及返回的JSON数据的格式,这样才能在我们的爬虫中使用这些数据。

关于如何从网络API中获取JSON格式的数据并提取出我们需要的内容,在之前的《文件和异常》一文中已经讲解过了,这里不再进行赘述。

使用Selenium

尽管很多网站对自己的网络API接口进行了保护,增加了获取数据的难度,但是只要经过足够的努力,绝大多数还是可以被逆向工程的,但是在实际开发中,我们可以通过浏览器渲染引擎来避免这些繁琐的工作,WebKit就是一个利用的渲染引擎。

WebKit的代码始于1998年的KHTML项目,当时它是Konqueror浏览器的渲染引擎。2001年,苹果公司从这个项目的代码中衍生出了WebKit并应用于Safari浏览器,早期的Chrome浏览器也使用了该内核。在Python中,我们可以通过Qt框架获得WebKit引擎并使用它来渲染页面获得动态内容,关于这个内容请大家自行阅读《爬虫技术:动态页面抓取超级指南》一文。

如果没有打算用上面所说的方式来渲染页面并获得动态内容,其实还有一种替代方案就是使用自动化测试工具Selenium,它提供了浏览器自动化的API接口,这样就可以通过操控浏览器来获取动态内容。首先可以使用pip来安装Selenium。

pip3 install selenium

下面以“阿里V任务”的“直播服务”为例,来演示如何使用Selenium获取到动态内容并抓取主播图片。

import requests
from bs4 import BeautifulSoup
def main():
 resp=requests.get('https://v.taobao.com/v/content/live?catetype=704&from=taonvlang')
 soup=BeautifulSoup(resp.text, 'lxml')
 for img_tag in soup.select('img[src]'):
 print(img_tag.attrs['src'])
if __name__=='__main__':
 main()

运行上面的程序会发现没有任何的输出,因为页面的HTML代码上根本找不到<img>标签。接下来我们使用Selenium来获取到页面上的动态内容,再提取主播图片。

from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
def main():
 driver=webdriver.Chrome()
 driver.get('https://v.taobao.com/v/content/live?catetype=704&from=taonvlang')
 soup=BeautifulSoup(driver.page_source, 'lxml')
 for img_tag in soup.body.select('img[src]'):
 print(img_tag.attrs['src'])
if __name__=='__main__':
 main()

在上面的程序中,我们通过Selenium实现对Chrome浏览器的操控,如果要操控其他的浏览器,可以创对应的浏览器对象,例如Firefox、IE等。运行上面的程序,如果看到如下所示的错误提示,那是说明我们还没有将Chrome浏览器的驱动添加到PATH环境变量中,也没有在程序中指定Chrome浏览器驱动所在的位置。

selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in PATH. Please see https://sites.google.com/a/chromium.org/chromedriver/home

为了解决上面的问题,可以到Selenium的官方网站找到浏览器驱动的下载链接并下载需要的驱动,在Linux或macOS系统下可以通过下面的命令来设置PATH环境变量,Windows下配置环境变量也非常简单,不清楚的可以自行了解。

export PATH=$PATH:/Users/Hao/Downloads/Tools/chromedriver/

其中/Users/Hao/Downloads/Tools/chromedriver/就是chromedriver所在的路径。

eautiful Soup 包:

Beautiful Soup: Python 的第三方插件用来提取 xml 和 HTML 中的数据。官网地址 https://www.crummy.com/software/BeautifulSoup/

1、安装 Beautiful Soup

打开 cmd(命令提示符),进入到 Python(Python2.7版本)安装目录中的 scripts 下,输入 dir 查看是否有 pip.exe, 如果用就可以使用 Python 自带的 pip 命令进行安装,输入以下命令进行安装即可:

pip install beautifulsoup4

2、测试是否安装成功

编写一个 Python 文件,输入:

import bs4

print bs4

运行该文件,如果能够正常输出则安装成功。

五、使用 Beautiful Soup 解析 html 文件

# -*- coding: UTF-8 -*-
import bs4
import re

from bs4 import BeautifulSoup

html_doc="""
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
# 创建一个BeautifulSoup解析对象
soup=BeautifulSoup(html_doc, "html.parser", from_encoding="utf-8")
# 获取所有的链接
links=soup.find_all('a')
print("所有的链接")

for link in links:
    print(link.name, link['href'], link.get_text())

print("获取特定的URL地址")
link_node=soup.find('a', href="http://example.com/elsie")
print(link_node.name, link_node['href'], link_node['class'], link_node.get_text())

print("正则表达式匹配")

link_node=soup.find('a', href=re.compile(r"ti"))
print(link_node.name, link_node['href'], link_node['class'], link_node.get_text())

print("获取P段落的文字")

p_node=soup.find('p', class_='story')
print(p_node.name, p_node['class'], p_node.get_text())

===========

输出: