数据解析
Spider常用知识
二.数据解析
1.正则
贪婪匹配和惰性匹配
.* 贪婪匹配, 尽可能多的去匹配结果
.*? 惰性匹配, 尽可能少的去匹配结果 -> 回溯
这两个要着重的说一下. 因为我们写爬虫用的最多的就是这个惰性匹配.
re模块中我们只需要记住这么几个功能就足够我们使用了.
-
findall 查找所有. 返回list
lst = re.findall("m", "mai le fo len, mai ni mei!") print(lst) # ['m', 'm', 'm'] lst = re.findall(r"\d+", "5点之前. 你要给我5000万") print(lst) # ['5', '5000'] -
search 会进行匹配. 但是如果匹配到了第一个结果. 就会返回这个结果. 如果匹配不上search返回的则是None
ret = re.search(r'\d', '5点之前. 你要给我5000万').group() print(ret) # 5 -
match 只能从字符串的开头进行匹配
ret = re.match('a', 'abc').group() print(ret) # a -
finditer, 和findall差不多. 只不过这时返回的是迭代器(重点)
it = re.finditer("m", "mai le fo len, mai ni mei!") for el in it: print(el.group()) # 依然需要分组 -
compile() 可以将一个长长的正则进行预加载. 方便后面的使用
obj = re.compile(r'\d{3}') # 将正则表达式编译成为一个 正则表达式对象, 规则要匹配的是3个数字 ret = obj.search('abc123eeee') # 正则表达式对象调用search, 参数为待匹配的字符串 print(ret.group()) # 结果: 123 -
正则中的内容如何单独提取?
单独获取到正则中的具体内容可以给分组起名字
s = """ <div class='西游记'><span id='10010'>中国联通</span></div> """ obj = re.compile(r"<span id='(?P<id>\d+)'>(?P<name>\w+)</span>", re.S) result = obj.search(s) print(result.group()) # 结果: <span id='10010'>中国联通</span> print(result.group("id")) # 结果: 10010 # 获取id组的内容 print(result.group("name")) # 结果: 中国联通 # 获取name组的内容这里可以看到我们可以通过使用分组. 来对正则匹配到的内容进一步的进行筛选.
案例(免费代理池抓取)
import requests
import re
url="http://www.66ip.cn/mo.php?sxb=&tqsl=50&port=&export=&ktip=&sxa=&submit=%CC%E1++%C8%A1&textarea="
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
}
f=open("ips.csv",mode="a",encoding="utf-8")
for i in range(10):
resp=requests.get(url,headers=headers)
page_sourse=resp.text
obj=re.compile(r"var mediav_ad_height = '60';.*?</script>(?P<ipss>.*?)</div>",re.S)
result=obj.search(page_sourse)
ips=result.group("ipss").strip().replace("\r","").replace("\n","").replace("\t","").split("<br />")[0:-1]
for ip in ips:
f.write(f"{ip}\n")
f.close()
2.bs4
bs4模块安装
pip install bs4
语法:
find(标签, 属性=值)
意思是在页面中查找 xxx标签, 并且标签的xxx属性必须是xxx值
例:
find('div', age=18) 含义: 在页面中查找div标签, 并且属性age必须是18的这个标签.
find_all()的用法和find()几乎一致. find()查找1个. find_all()查找页面中所有的.
<div class="honor">
page.find("div", class="honor")
注意, python中class是关键字. 会报错的. 怎么办呢? 可以在class后面加个下划线
page.find("div", class_="honor")
我们可以使用第二种写法来避免这类问题出现
page.find("div", attrs={"class": "honor"})
方法:
#提取文本
find().text
#提取属性
find().get("属性标签")
示例代码:
html = """
<ul>
<li><a href="zhangwuji.com">张无忌</a></li>
<li id="abc"><a href="zhouxingchi.com">周星驰</a></li>
<li><a href="zhubajie.com">猪八戒</a></li>
<li><a href="wuzetian.com">武则天</a></li>
</ul>
"""
from bs4 import BeautifulSoup
page = BeautifulSoup(html, "html.parser")
lis = page.find_all("li")
for li in lis:
print(li.find("a").get("href"))
案例
import requests
from bs4 import BeautifulSoup
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
}
url="https://movie.douban.com/top250"
resp=requests.get(url,headers=headers)
page=BeautifulSoup(resp.text)
lis=page.find_all("div",class_="info")
for li in lis:
print(li.find_next("span",class_="title").text)
print(li.find_next("div",class_="hd").find_next("a").get("href"))
3.xpath
安装lxml模块.
pip install lxml
用法:
- 将要解析的html内容构造出etree对象.
- 使用etree对象的xpath()方法配合xpath表达式来完成对数据的提取
案例
import requests
from lxml import etree
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
}
url="https://movie.douban.com/top250"
resp=requests.get(url,headers=headers)
#构造etree对象
tree=etree.HTML(resp.text)
lis=tree.xpath("//div[@class='item']")
with open("dbxpath.csv",mode='w',encoding='utf-8')as f:
for li in lis:
#提取文本
name=li.xpath("./div[2]/div/a/span[1]/text()")[0]
#提取属性
href=li.xpath("./div/a/@href")[0]
f.write(f"{name},{href}\n")

浙公网安备 33010602011771号