几种数据解析对比

解析工具 解析速度 使用难度
BeautifulSoup 最慢 最简单
lxml 简单
正则表达式 最快 最难

lxml—-xpath

Xpath

xpath(XML Path Language):一门在XML和HTML文档中查找信息的语言,可用来在XML和HTML文档中对元素和属性进行遍历。Xpath有七种类型节点:元素、属性、文本、命名空间、处理指令、注释以及文档根节点。

  • xpath浏览器常用工具:
    • Chrome工具:XPath Helper
    • Firefox工具:Try XPath

      Xpath基础语法

      | 表达式 | 描述 | 示例 | | —- | —- | —- | | nodename | 选取此节点所有的子节点 | bookstore | | / | 如果在最前面,代表从根节点选取。否则选择某节点下的某个节点 | /bookstore | | // | 从全局节点中选择节点,随便在哪个位置 | //book | | @ | 选取某个节点的属性 | //book[@price] |

Xpath谓语

路径表达式 结果
/bookstore/book[1] 选第一个book
/bookstore/book[last()] 选最后一个book
/bookstore/book[last()-1] 选倒数第二个book
/bookstore/book[position()<3] 选取前两个book
//title[@lang] 选取拥有lang属性的title
//title[@lang=’en’] 选取lang属性等于en的title
/bookstore/book[price>35.00] 选取price值大于35的book
/bookstore/book[price>35.00]/title 选取price值大于35的book的title

Xpath通配符

通配符 描述
* 匹配任意节点
@* 匹配节点中的任何属性

Xpath运算符

运算符 描述 实例
| 一次选中多个集合 //book | //cd
+ 加法 6 + 4
- 减法 6 - 4
* 乘法 6 * 4
div 除法 8 div 4
mod 计算除法余数 5 mod 2

还有一些比较运算符返回的是布尔型的值:=、!=、<、<=、>、>=、or、and

lxml库

lxml是一个HTML/XML的解析器。解析HTML代码的时候,如果HTML代码不规范,他会自动进行补全。

lxml库基本使用

  1. from lxml import etree
  2. text = """
  3. <div>
  4. <ul>
  5. <li class="item-0"><a href="index.html"></a></li>
  6. <li class="item-1"><a href="index.html"></a></li>
  7. <li class="item-2"><a href="index.html"></a>
  8. </ul>
  9. </div>
  10. """
  11. # 将字符串解析为HTML文档
  12. html = etree.HTML(text)
  13. print(html)
  14. # 将字符串系列化html
  15. result = etree.tostring(html).decode('utf-8')
  16. print(result)
  17. # 从文件中读取html,如果不能因为html文件的规范问题不能直接读取,那我们需要加入第一行,指定编码方式
  18. parse = etree.HTMLParser(encoding='utf-8')
  19. html = etree.parse('Xpath-test.html', parser=parse)
  20. print(etree.tostring(html).decode('utf-8'))

lxml使用Xpath语法

如下是一个html文件的简单例子:

  1. <!-- hello.thml -->
  2. <div>
  3. <ul>
  4. <li class="item-0"><a href="link1.html">first item</a></li>
  5. <li class="item-1"><a href="link2.html">second item</a></li>
  6. <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li>
  7. <li class="item-0"><a href="link4.html">fourth item</a></li>
  8. <li class="item-0"><a href="link5.html">fifth item</a></li>
  9. </ul>
  10. </div>

代码使用xpath例子如下:

  1. from lxml import etree
  2. html = etree.parse('hello.html')
  3. # 获取所有li标签
  4. result = html.xpath('//li')
  5. for i in result:
  6. print(etree.tostring(i))
  7. # 获取所有li标签下所有class属性值
  8. result = html.xpath('//li/@class')
  9. # 获取li标签下href为www.baidu.com的a标签,找不到会返回空列表
  10. result = html.xpath('//li/a[@href="www.baidu.com"]')
  11. # 获取li下所有span标签
  12. result = html.xpath('//li//span')
  13. # 获取li下所有a标签里的class
  14. result = html.xpath('//li/a//@class')
  15. # 获取最后一个li的a标签的href值
  16. result = html.xpath('//li[last()]/a/@href')
  17. # 获取倒数第二个li元素的内容
  18. result0 = html.xpath('//li[last()-1]/a')
  19. print(result0[0].text)
  20. result1 = html.xpath('//li[last()-1]/a/text()')
  21. print(result1)

BeautifulSoup4

安装

  1. pip install bs4

和lxml一样,Beautiful Soup也是一个HTML/XML的解析器,主要功能也是解析和提取数据。lxml只会局部遍历,而Beautiful Soup是基于HTML DOM(Document Object Model)的,会载入整个文档,解析整个DOM树,因此时间和内存开销会大很多,所以性能低于lxml。
使用BeautifulSoup4也要安装lxml,所以我不是很喜欢,这里不做记录,需要使用的话自己百度吧!


re模块—-正则表达式

正则表达式

单字符串匹配规则

字符 描述
任意字符 输入谁,匹配谁
.(点) 匹配任意的字符(除了’\n’)
\d 匹配任意的数字
\D 匹配任意的非数字
\s 匹配空白字符(包括:\n,\t,\r和空格)
\S 匹配非空白字符
\w 匹配的是a-z和A-Z以及数字和下划线
\W 匹配的和’\w’相反
[] 组合的方式,只要满足中括号中的某一项都算匹配成功(如:[a-zA-Z0-9],[^a-zA-Z0-9])

多字符匹配

字符 匹配
* 匹配前一个字符0次或者无限次
+ 匹配前一个字符1次或者无限次
? 匹配前一个字符0次或者1次
{m}/{m, n} 匹配前一个字符m次或者m到n次

开始、结束、贪婪、非贪婪

字符 描述
^ 以…开始
$ 以…结束
? 默认为贪婪匹配,加上’?’为非贪婪匹配(这个’?’与表示次数的’?’不同,这个必须放在表示次数的符号后,如: *? +? ??。)

转义字符和原生字符串

Python中的转义字符‘\‘原生字符串通过在字符串之前加字母‘r’表示,如:r”abc\n”
正则表达式中,转义字符也是‘\‘

通过Python使用正则表达式时,有时会因为转义而出现一些问题,如下例子:

  1. import re
  2. text = "\cab c"
  3. res = re.match("\\c", text)
  4. print(res.group())

观察上述代码可以发现,我们的意图是想匹配text开头的’\c’字符串,但在执行时却报错了。这是因为使用Python执行上述代码时,”\\c”经过Python的转义,变为了”\c”,之后再进入正则表达式的转义,这时已经没有转义字符了,自然解析就出了问题。解决办法有两个,如下:

  1. # 解决办法一:计算两层转义该写几个'\'
  2. res = re.match("\\\\c", text)
  3. # 解决办法二:使用原生字符
  4. res = re.match(r"\\c", text)

使用原生字符后,就没有Python转义这一步骤了。所以,在应用过程中,我们建议多使用原生字符。

分组——正则表达式中加入括号

如果想具体的分组提取,如下例子:

  1. import re
  2. text = "apple price is $99, orange price is $88"
  3. result = re.search('.+(\$\d+).+(\$\d+)', text)
  4. print(result.group()) # 输出:apple price is $99, orange price is $88
  5. print(result.group(0)) # group()/group(0)都匹配整个分组
  6. print(result.group(1)) # 输出:$99
  7. print(result.group(2)) # 输出:$88
  8. print(result.groups()) # 输出:('$99', '$88')

re模块常用方法

方法 描述
compile() 将正则表达式提前编译好,返回一个对象,提高程序运行效率
match() 在字符串开始的位置匹配,若比配失败,返回None
search() 找到第一个匹配的值返回,找不到返回None
findall() 返回所有满足条件的匹配项,找不到返回None
finditer() 搜索字符串,返回一个Match对象的迭代器
split() 按照匹配的子串,将string分割后返回列表
sub() 替换字符串中每一个匹配的子串后,返回替换后的字符串
  1. import re
  2. text = "apple price is $99, orange price is $88"
  3. rr = re.compile(r'\$\d+')
  4. res1 = rr.findall(text)
  5. print(res1) # 输出:['$99', '$88']
  6. res2 = re.match(r'\w+ \w+', text)
  7. print(res2.group()) # 输出:apple price
  8. res3 = re.search(r'\$\d+', text)
  9. print(res3.group()) # 输出:$99
  10. res4 = re.findall(r'\$\d+', text)
  11. print(res4) # 输出:['$99', '$88']
  12. res5 = re.finditer(r'\$\d+', text)
  13. print('----------------------')
  14. for i in res5:
  15. print(i.group()) # 输出:$99\n$88
  16. print('----------------------')
  17. res6 = re.split(r' |,', text)
  18. print(res6) # 输出:['apple', 'price', 'is', '$99', '', 'orange', 'price', 'is', '$88']
  19. res7 = re.sub(r' |,', '*', text)
  20. print(res7) # 输出:apple*price*is*$99**orange*price*is*$88
  21. # -----------------------------------------------------------------------------
  22. # ------如果要加注释,使用的方法的最后加上re.VERBOSE
  23. # ------如果要 . 能表示所有字符,包括 '\n',那使用的方法的最后加上re.DOTALL
  24. #---------------------------具体例子如下---------------------------------
  25. houses = re.findall(r"""
  26. <li.*?house-cell.*?<a.*?strongbox.*?>(.*?)</a> # 房源标题
  27. .*?<p.*?room.*?>(.*?)</p> # 户型大小
  28. .*?money.*?strongbox.*?>(.*?</b>.*?)</div> # 价格
  29. """, text, re.VERBOSE|re.DOTALL)
  30. # -----------------------------------------------------------------------------