python爬虫模块(RE、BS4、Xpath)
一、RE模块
基本使用:
findall
:匹配字符串中所有符合正则的内容
finditer
:匹配内容后返回迭代器,从迭代器中取数据可以用循环加.group()
search
:找到一个结果就返回,返回的结果是match对象,取数据可以用.group()
match
:从头开始匹配,从第一个字母匹配不到就没有(不常用)
其中,上述内容的调用通过:
ret=re.findall(r'正则串','匹配目标串')
实现调用。
预加载:
预加载正则表达式
(用于正则表达式较长、且多次使用时的封装)
格式为:
1 2 3 4
| obj = re.compile(r"\d+") ret = obj.finditer("目标字串666") for it in ret: print(it.group())
|
内容提取:
正则可以用来匹配固定格式的一串字符串,如<html>xxx<html>
,然而当我们不想要两侧的,只想要xxx时,需要从正则中取出不重复信息,即内容提取。
举例说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| str=""" <div class='aa'><span id='1'>qwe</span><div> <div class='bb'><span id='2'>qwer</span><div> <div class='cc'><span id='3'>qwert</span><div> <div class='dd'><span id='4'>qwerty</span><div> <div class='ee'><span id='5'>qwertyu<span><div> """
obj = re.compile(r"<div class='(?p<name1>.*?)'><span id='(?P<name2>\d+)'>(?P<name3>.*?)</span><div>",re.S) result = obj.finditer(s)
for it in result: print(it.group('name1')) print(it.group('name2')) print(it.group('name3'))
|
即,使用(?P<分组名字>原来正则)
从正则匹配的内容中进一步提取内容。
二、BS4模块
引入方式:
1
| from bs4 import BeautifulSoup
|
使用方式(以抓取表格为例):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
import requests from bs4 import BeautifulSoup import csv
url = "http://www.xxx.com/a.html" resp = requests.get(url)
page = BeautifulSoup(resp.text, "html.parser")
table = page.find("table", attrs={"class": "hq_table"}) trs = table.find_all("tr")[1:] for tr in trs: target_1 = tr.find_all("td") target_2 = tds[0].text target_3 = tds[1].text target_4 = tds[2].text target_5 = tds[3].text target_6 = tds[4].text target_7 = tds[5].text target_8 = tds[6].text print(name, low, avg, high, gui, kind, date)
print("over!")
|
核心方法:
find(标签, 属性=值)
find_all(标签, 属性=值)
按照次序填写要找的标签名和属性名即可。其中,标签名的传参为字符串,属性名由于class、id
等是python的关键字,可以使用attrs={键值对}
来代替,键值对的键和值均为字符串。
三、Xpath模块
Xpath是XML文档中搜索的一门语言,html是XML的子集
模块引入:
具体使用:
若xml为一个字符串形式的,有标签节点组成的xml字符串,从中提取信息可以遵循这样的语法:
注:Xpath的定位在开发者工具中右键复制选项,可实现智能定位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| from lxml import etree
xml = """ <book> <id>1</id> <name>野花遍地香</name> <price>1.23</price> <nick>臭豆腐</nick> <author> <nick id="10086">周大强</nick> <nick id="10010">周芷若</nick> <nick class="joy">周杰伦</nick> <nick class="jolin">蔡依林</nick> <div> <nick>TTTarget1</nick> </div> <span> <nick>TTTarget2</nick> <div> <nick>TTTarget3</nick> </div> </span> </author>
<partner> <nick id="ppc1">AAAAim1</nick> <nick id="pbc2">AAAAim2</nick> <nick id="pbc3">AAAAim3</nick> <nick id="pbc4">AAAAim4</nick> </partner> </book> """
tree = etree.XML(xml)
result1 = tree.xpath("/book")
result2 = tree.xpath("/book/name/text()")
result3 = tree.xpath("/book/author//nick/text()")
result4 = tree.xpath("/book/author/*/nick/text()")
result5 = tree.xpath("/book/partner/nick[1]/text()")
result6 = tree.xpath("/book/partner/nick[@id="pbc2"]/text()")
result7 = tree.xpath("/book/partner/nick/@id") print(result)
|
其中//
代表任意的子集(可以是一层或多层),只要存在就能找到;
而/*/
代表且只能代表任意一层。
举例说:
代码块中,result4
可以匹配到TTTarget1
、TTTarget2
、TTTarget
。
但result5
只能匹配到TTTarget1
、TTTarget2
,不能匹配到TTTarget3
。
当使用../xxx[n]/../text()
语法时,一定要记住这里的n是从1开始计数,如代码块中匹配到的就是AAAAim1
,并非AAAAim2
!
注意,当筛选两次,即使用如下语法
1 2 3 4
| ol_li_list = tree.xpath("/html/body/ol/li") for li in ol_li_list: result = li.xpath("./a/text()") print(result2)
|
在相对查找时,需要使用./
而非/
以表示相对路径!