介概述:
使用特定引擎解析网页里面得数据,根据规则提取入库
常见的技术:
正则、xpath、pyquery、Beautiful Soup4
开源测试工具 http://tool.oschina.net/regex/
官网:https://docs.python.org/zh-cn/3/library/re.html
. | 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。 |
\d | 匹配一个数字字符。等价于 [0-9]。 |
\D | 匹配一个非数字字符。等价于 [^0-9]。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 |
\w | 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 |
\W | 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。 |
1、match
用法: 提取关键参数 比如 token sign 后端返回得签名信息 算法
import re
content = 'Hello 123 456 welcome to world'
print(len(content))
result = re.match('^Hello\s\d\d\d\s\d{3}\s\w{7}', content)
print(result)
print(result.group())
print(result.span())
方法 | 说明 |
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组 |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号 |
1)匹配数字
import re
content = 'Hello 123456 welcome to world'
result = re.match('^Hello\s(\d+)\swelcome', content)
print(result)
print(result.group(1))
print(result.span())
2)通用匹配
import re
content = 'Hello 123 456 welcome to world'
# 匹配所有数据
result = re.match('^Hello.*ng$', content)
# 匹配某某开始到某某结束
result = re.match('^Hello(.*)ng$', content).group(1)
print(result)
print(result.group())
print(result.span())
3)贪婪和非贪婪
import re
content1 = 'http://xxxxx.com/yyds/baidu'
result2 = re.match('http.*com/(.*?)s', content1)
result2 = re.match('http.*?com/(.*)s', content1)
print('result1', result1.group())
print('result2', result2.group())
4)修饰符
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |
import re
# 这个修饰符的作用是匹配包括换行符在内的所有字符。
content = '''Hello 1234567 World_This
is a Regex Demo
'''
result = re.match('^He.*?(\d+).*?Demo$', content)
result = re.match('^He.*?(\d+).*?Demo$', content,re.S)
print(result.group())
2、search
用法: 提取数据
re模块中的search函数对整个字符串进行扫描并返回第一个匹配的结果。从左到右进行扫描
1)匹配数据
text = '人生苦短,我用pythons'
res1 = re.search('python',text)
data = 'result:{"name":"王五","age":"20"}'
res3 = re.search("{.*?}",data)
2)正则提取案例
地址:https://finance.ifeng.com/c/8HzIujEasuH
url = 'https://finance.ifeng.com/c/8HzIujEasuH'
from utils.base import Spider
res = Spider().fetch(url)
import re
# 不带符号
# text = re.findall('var allData = {(.*)};',res.text)
# 带符号
# text = re.findall('var allData\s=\s(.*);',res.text)
3)匹配中文
[\u4e00-\u9fa5]
s = '大家晚上好asdasdsad'
aa = re.findall('[\u4e00-\u9fa5]+',s)
环境安装
pip install pyquery
利用它,我们可以直接解析 DOM 节点的结构,并通过 DOM 节点的一些属性快速进行内容提取。
html = '''
<div id="cont">
<ul class="slist">
<li class="item-0">web开发</li>
<li class="item-1"><a href="link2.html">爬虫开发</a></li>
<li class="item-0 active"><a href="link3.html"><span class="bold">数据分析</span></a></li>
<li class="item-1 active"><a href="link4.html">深度学习</a></li>
<li class="item-0"><a href="link5.html">机器学习</a></li>
</ul>
</div>
'''
1、实例演示
from pyquery import PyQuery as pq
doc = pq(html)
print(doc('li'))
2、css选择器
doc = pq(html)
print(doc('#cont .slist li'))
print(type(doc('#cont .slist li')))
3、提取内容
for item in doc('#cont .slist li').items():
print(item.text())
4、子节点
from pyquery import PyQuery as pq
doc = pq(html)
items = doc('.slist')
print(type(items))
print(items) # 提取节点所有内容
lis = items.find('li') # 获取符合条件的li标签
print(type(lis))
print(lis)
5、 属性获取
from pyquery import PyQuery as pq
doc = pq(html)
a = doc('.item-0.active a')
print(a, type(a))
print(a.attr('href'))
6、遍历提取
doc = pq(html)
a = doc('a')
for s in a.items():
print(s.attr('href')) # 属性获取
print(s.text()) # 值获取
插件下载:https://chrome.zzzmh.cn/index#/search
XPath 的选择功能十分强大,它提供了非常简洁明了的路径选择表达式。另外,它还提供了超过 100 个内建函数,用于字符串、数值、时间的匹配以及节点、序列的处理等。几乎所有我们想要定位的节点,都可以用 XPath 来选择。
官网:https://www.w3.org/TR/xpath/
安装xpath解析库:
pip install lxml
表 3-1 XPath 常用规则
表 达 式 | 描 述 |
nodename | 选取此节点的所有子节点 |
/ | 从当前节点选取直接子节点 |
// | 从当前节点选取子孙节点 |
. | 选取当前节点 |
.. | 选取当前节点的父节点 |
@ | 选取属性 |
案例演示
text = '''
<div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</ul>
</div>
'''
1、解析
from lxml import etree
html = etree.HTML(text)
result = etree.tostring(html)
print(result.decode('utf-8'))
2、节点操作
我们一般会用 // 开头的 XPath 规则来选取所有符合要求的节点。这里以前面的 HTML 文本为例,如果要选取所有节点,可以这样实现:
这里使用 * 代表匹配所有节点,也就是整个 HTML 文本中的所有节点都会被获取。可以看到,返回形式是一个列表,每个元素是 Element 类型,其后跟了节点的名称,如 html、body、div、ul、li、a 等,所有节点都包含在列表中了。
result = html.xpath('//*')
3、子节点
result = html.xpath('//li/a')
result = html.xpath('//li/a/text()') # 提取数据
result = html.xpath('//li/a/@href') # 属性值
4、指定节点获取
result = html.xpath('//li[@class="item-0"]/a/text()')
print(result)
# ['first item', 'fifth item']
5、匹配翻页元素
# 最后一个
//div[@class="page"]/a[last()-1]
# 下一页
//div[@class="page"]/a[text()="下一页>"]/@href
6、案例演示
• 说明:提取当前网站的首页标题信息,要求使用xpath解析器
from lxml import etree
url1= 'https://www.icswb.com/channel-list-channel-162.html'
res4 = Spider().fetch(url=url1)
html = etree.HTML(res4.text)
li = html.xpath('//ul[@id="NewsListContainer"]/li')
for i in li:
href = i.xpath('./h3/a/text()')
print(href)
简单来说,BeautifulSoup 就是 Python 的一个 HTML 或 XML 的解析库,我们可以用它来方便地从网页中提取数据,官方的解释如下:
BeautifulSoup 提供一些简单的、Python 式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。
BeautifulSoup 自动将输入文档转换为 Unicode 编码,输出文档转换为 utf-8 编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时你仅仅需要说明一下原始编码方式就可以了。
BeautifulSoup 已成为和 lxml、html5lib 一样出色的 Python 解释器,为用户灵活地提供不同的解析策略或强劲的速度。
表 4-1 Beautiful Soup 支持的解析器
解析器 | 使用方法 | 优势 | 劣势 |
Python 标准库 | BeautifulSoup(markup, "html.parser") | Python 的内置标准库、执行速度适中 、文档容错能力强 | Python 2.7.3 or 3.2.2) 前的版本中文容错能力差 |
LXML HTML 解析器 | BeautifulSoup(markup, "lxml") | 速度快、文档容错能力强 | 需要安装 C 语言库 |
LXML XML 解析器 | BeautifulSoup(markup, "xml") | 速度快、唯一支持 XML 的解析器 | 需要安装 C 语言库 |
html5lib | BeautifulSoup(markup, "html5lib") | 最好的容错性、以浏览器的方式解析文档、生成 HTML5 格式的文档 | 速度慢、不依赖外部扩展 |
通过以上对比可以看出,lxml 解析器有解析 HTML 和 XML 的功能,而且速度快,容错能力强,所以推荐
1、安装
pip install beautifulsoup4
2、demo
from bs4 import BeautifulSoup
# 2个参数 html 文本 解析引擎
soup = BeautifulSoup('<p>Hello world</p>', 'lxml')
print(soup.p.string)
3、节点选择器
直接调用节点的名称就可以选择节点元素,再调用 string 属性就可以得到节点内的文本了,这种选择方式速度非常快。如果单个节点结构层次非常清晰,可以选用这种方式来解析。
下面再用一个例子详细说明选择元素的方法:
html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.title)
print(type(soup.title))
print(soup.title.string)
print(soup.head)
print(soup.p)
4、获取属性
每个节点可能有多个属性,比如 id 和 class 等,选择这个节点元素后,可以调用 attrs 获取所有属性:
print(soup.p.attrs)
print(soup.p.attrs['name'])
5、嵌套选择
html = """
<html><head><title>The Dormouse's story</title></head>
<body>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.head.title)
print(type(soup.head.title))
print(soup.head.title.string)
6、select(根据选择器选取指定内容)
标签选择器(a),类选择器(.dudu),id选择器(#lala),组合选择器(a, .dudu, #lala, .meme),层级选择器(div.dudu#lala.meme.xixi 表示下面好多级和 div>p>a>.lala 只能是下面一级 ),伪类选择器(不常用),属性选择器 (input[name=‘lala’])
1)样例
htmls = """
<html>
<head>
<title>The Dormouse's story</title>
</head>
<body>
<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" title="xl">
<span>Elsie</span>
</a>
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a>
and
<a href="http://example.com/tillie" class="sister" id="link3" rel="noopener noreferrer ">Tillie</a>
and they lived at the bottom of a well.
</p>
<p class="story">...</p>
"""
2)层级选择器
soup.select('.story > a > span')[0].text
3)id选择器
print(soup.select('#link1'))
4)提取属性
soup.select('#link1')[0].attrs['href']
5)属性选择器
print(soup.select("input[type='password']"))
6)提取实际数据
义上讲,爬虫只负责抓取,也就是下载网页。而实际上,爬虫还要负责从下载的网页中提取我们想要的数据,即对非结构化的数据(网页)进行解析提取出结构化的数据(有用数据)。
所以说,网页下载下来只是第一步,还有重要的一步就是数据提取。不同的爬虫想要的数据不一样,提取的数据也就不一样,但提取方法都是类似的。
最简单的提取数据的方法,就是使用正则表达式,此种方法简单,提取的逻辑也不能复杂,不然写出的正则表达式就晦涩难懂,甚至不能提取复杂的数据结构。
最终,老猿经过多年的使用经验,选择了lxml和xpath来解析网页提取结构化数据。顺便说一下 BeautifulSoup,它也是一个很棒的解析HTML的工具,可以使用多个解析器,比如Python标准库的parser,但是速度比较慢,也可以使用lxml作为解析器,但是它的使用方法、API跟lxml不太一样。使用下来,还是lxml的API更舒服。
lxml 对C语言库 libxml2和 libxslt进行绑定,提供了Pythonic的API,它有一些主要特点:
总结为一句话就是,C语言的速度和Python的简易相结合的神器。
lxml有两大部分,分别支持XML和HTML的解析:
lxml.etree可以用来解析RSS feed,它就是一个XML格式的文档。然而爬虫抓取的绝大部分都是html网页,所以,我们这里主要讲述lxml.html解析网页的方法。
我们下载得到的网页就是一串html字符串,如何把它输入给lxml.html模块,从而生成html文档的树结构呢?
该模块提供了几种不同的方法:
下面我们通过具体示例来说明上面几个方法的不同。
document_fromstring 的使用方法
In [1]: import lxml.html as lh In [2]: z = lh.document_fromstring('<span>abc</span><span>xyz</span>') # 可以看到,它自动加了根节点<html> In [3]: z Out[3]: <Element html at 0x7fc410667b88> In [4]: z.tag Out[4]: 'html' # 还加了<body>节点 In [5]: z.getchildren() Out[5]: [<Element body at 0x7fc4101a3ae8>] # 把字符串的两个节点放在了<body>里面 In [6]: z.getchildren()[0].getchildren() Out[6]: [<Element span at 0x7fc410092bd8>, <Element span at 0x7fc410667c28>]
fragment_fromstring 的使用
In [11]: z = lh.fragment_fromstring(‘<div>abc</div><div>xyz</div>’) --------------------------------------------------------------------------- ParserError Traceback (most recent call last) <ipython-input-11-a11f9a0f71d1> in <module>() ----> 1 z = lh.fragment_fromstring(‘<div>abc</div><div>xyz</div>’) ~/.virtualenvs/py3.6/lib/python3.6/site-packages/lxml/html/__init__.py in fragment_fromstring(html, create_parent, base_url, parser, **kw) 850 raise etree.ParserError( 851 “Multiple elements found (%s)” --> 852 % ‘, ‘.join([_element_name(e) for e in elements])) 853 el = elements[0] 854 if el.tail and el.tail.strip(): ParserError: Multiple elements found (div, div) # 可以看到,输入是两个节点(element)时就会报错 # 如果加上 create_parent 参数,就没问题了 In [12]: z = lh.fragment_fromstring('<div>abc</div><div>xyz</div>', create_parent='p') In [13]: z.tag Out[13]: 'p' In [14]: z.getchildren() Out[14]: [<Element div at 0x7fc40a41a818>, <Element div at 0x7fc40a41aea8>]
fragments_fromstring 的使用
# 输入字符串含有一个节点,则返回包含这一个节点的列表 In [17]: lh.fragments_fromstring('<div>abc</div>') Out[17]: [<Element div at 0x7fc40a124ea8>] # 输入字符串含有多个节点,则返回包含这多个节点的列表 In [18]: lh.fragments_fromstring('<div>abc</div><div>xyz</div>') Out[18]: [<Element div at 0x7fc40a124b88>, <Element div at 0x7fc40a124f98>]
fromstring 的使用
In [27]: z = lh.fromstring('<div>abc</div><div>xyz</div>') In [28]: z Out[28]: <Element div at 0x7fc40a0eb368> In [29]: z.getchildren() Out[29]: [<Element div at 0x7fc410135548>, <Element div at 0x7fc40a0eb2c8>] In [30]: type(z) Out[30]: lxml.html.HtmlElement
这里,fromstring输入的如果是多个节点,它会给加一个父节点并返回。但是像html网页都是从节点开始的,我们使用fromstring() 和 document_fromstring() 都可以得到完整的网页结构。
从上面代码中我们可以看到,那几个函数返回的都是HtmlElement对象,也就是说,我们已经学会了如何从html字符串得到HtmlElement的对象,下一节我们将学习如何操作HtmlElement对象,从中提取我们感兴趣的数据。
源:Python数据之道
作者:Peter
整理:阳哥
大家好,我是阳哥。
今天来跟大家分享用 BeautifulSoup 获取信息的一些知识点,文章内容由公众号读者 Peter 创作。
欢迎各位童鞋向公众号投稿,点击下面图片了解详情!
爬虫,是学习Python的一个有用的分支,互联网时代,信息浩瀚如海,如果能够便捷的获取有用的信息,我们便有可能领先一步,而爬虫正是这样的一个工具。
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库。由于 BeautifulSoup 是基于 Python,所以相对来说速度会比另一个 Xpath 会慢点,但是其功能也是非常的强大,本文会介绍该库的基本使用方法,帮助读者快速入门。
网上有很多的学习资料,但是超详细学习内容还是非官网莫属,资料传送门:
英文官网:https://www.crummy.com/software/BeautifulSoup/bs4/doc/
中文官网:https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/
本文的主要内容如下:
安装
安装过程非常简单,直接使用pip即可:
pip install beautifulsoup4
上面安装库最后的4是不能省略的,因为还有另一个库叫作 beautifulsoup,但是这个库已经停止开发了。
因为BS4在解析数据的时候是需要依赖一定的解析器,所以还需要安装解析器,我们安装强大的lxml:
pip install lxml
在python交互式环境中导入库,没有报错的话,表示安装成功。
使用
使用过程直接导入库:
from bs4 import BeautifulSoup
解析原理
假设我们现在本地有一个HTML文件待解析,具体内容如下,数据中有各种HTML标签:html、head、body、div、p、a、ul、li等
from bs4 import BeautifulSoup
fp = open('./test.html','r',encoding='utf-8') # 打开本地文件
soup = BeautifulSoup(fp,'lxml')
soup
所有的数据解析都是基于soup对象的,下面开始介绍各种解析数据方法:
soup.TagName返回的是该标签第一次出现的内容,以a标签为例:
数据中多次出现a标签,但是只会返回第一次出现的内容
我们再看下div标签:
出现了2次,但是只会返回第一次的内容:
find()主要是有两个方法:
1、返回标签第一次出现的内容:
比如返回a标签第一次出现的内容:
再比如返回div标签第一次出现的内容:
2、属性定位
比如我们想查找a标签中id为“谷歌”的数据信息:
在BS4中规定,如果遇到要查询class情况,需要使用class_来代替:
但是如果我们使用attrs参数,则是不需要使用下划线的:
该方法返回的是指定标签下面的所有内容,而且是列表的形式;传入的方式是多种多样的。
1、传入单个指定的标签
image-20210523170401516
上面返回的是列表形式,我们可以获取我们想要的内容:
2、传入多个标签(列表形式)
需要主要返回内容的表达形式,每个标签的内容是单独显示的
3、传入正则表达式
比如查看以a开头标签的全部内容
查看以li标签开头的全部内容:
主要是有3种选择器,返回的内容都是列表形式
1、类选择器
2、id选择器
3、标签选择器
直接指定li标签
4、选择器和find_all()可以达到相同的效果:
soup.tagName和soup.find('tagName')的效果也是相同的:
在soup.select()方法中是可以使用层级选择器的,选择器可以是类、id、标签等,使用规则:
1、单层使用
2、多层使用
获取某个标签中对应文本内容主要是两个属性+一个方法:
1、text
2、string
3、get_text()
3者之间的区别
# text和get_text():获取标签下面的全部文本内容
# string:只能获取到标签下的直系文本内容
1、通过选择器来获取
2、通过find_all方法来获取
下面介绍的是通过BeautifulSoup解析方法来获取某个小说网站上古龙小说名称和对应的URL地址。
我们需要爬取的数据全部在这个网址下:https://www.kanunu8.com/zj/10867.html,右键“检查”,查看对应的源码,可以看到对应小说名和URL地址在源码中位置
每行3篇小说在一个tr标签下面,对应的属性href和文本内容就是我们想提取的内容。
import requests
from bs4 import BeautifulSoup
import pandas as pd
import re
url = 'https://www.kanunu8.com/zj/10867.html'
headers = {'user-agent': '个人请求头'}
response = requests.get(url = url,headers = headers)
result = response.content.decode('gbk') # 该网页需要通过gbk编码来解析数据
# result
soup1 = BeautifulSoup(result,'lxml')
# print(soup1.prettify()) 美化输出源码内容
1、先获取整体内容
两个信息全部指定a标签中,我们只需要获取到a标签,通过两个属性href和target即可锁定:
# 两个属性href和target,不同的方法来锁定
information_list = soup1.find_all('a',href=re.compile('^/book'),target='_blank')
information_list
2、再单独获取两个信息
通过属性来获取URL地址,通过文本来获取名称
url_list = []
name_list = []
for i in information_list:
url_list.append(i['href']) # 获取属性
name_list.append(i.text) # 获取文本
3、生成数据帧
gulong = pd.DataFrame({
"name":name_list,
"url":url_list}
)
gulong
我们发现每部小说的具体地址其实是有一个公共前缀的:https://www.kanunu8.com/book,现在给加上:
gulong['url'] = 'https://www.kanunu8.com/book' + gulong['url'] # 加上公共前缀
gulong.head()
另外,我们想把书名的《》给去掉,使用replace替代函数:
gulong["name"] = gulong["name"].apply(lambda x:x.replace("《","")) # 左边
gulong["name"] = gulong["name"].apply(lambda x:x.replace("》","")) # 右边
# 保存
gulong.to_csv("gulong.csv",index=False) # 保存到本地的csv文件
最后显示的前5行数据:
本文从BeautifulSoup4库的安装、原理以及案例解析,到最后结合一个实际的爬虫实现介绍了一个数据解析库的使用,文中介绍的内容只是该库的部分内容,方便使用者快速入门,希望对读者有所帮助。
*请认真填写需求信息,我们会在24小时内与您取得联系。