一、正则
1.元字符
. √匹配除换行符以外的任意字符, 未来在python的re模块中是一个坑.
\w √匹配字母或数字或下划线.
\s 匹配任意的空白符
\d √匹配数字
\n 匹配一个换行符
\t 匹配一个制表符
^ 匹配字符串的开始
$ 匹配字符串的结尾
\W 匹配非字母或数字或下划线
\D 匹配非数字
\S 匹配非空白符
a|b 匹配字符a或字符b
() √匹配括号内的表达式,也表示一个组
[...] √匹配字符组中的字符
[^...] 匹配除了字符组中字符的所有字符
控制元字符出现的次数
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
贪婪匹配与惰性匹配
.* 贪婪匹配, 尽可能多的去匹配结果
.*? 惰性匹配, 尽可能少的去匹配结果 -> 回溯
2.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
匹配第一个结果,匹配不到返回none
ret = re.search(r'\d', '5点之前. 你要给我5000万').group() print(ret) # 5
-
match
从字符串开头匹配ret = re.match('a', 'abc').group() print(ret) # a
-
finditer
查找所有返回迭代器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"))
-
正则替换
import re r = re.split(r"\d+", "我今年19岁了, 你知道么, 19岁就已经很大了. 周杰伦20岁就得奖了") print(r) # ['我今年', '岁了, 你知道么, ', '岁就已经很大了. 周杰伦', '岁就得奖了'] # 替换 r = re.sub(r"\d+", "18", "我今年19岁了, 你知道么, 19岁就已经很大了. 周杰伦20岁就得奖了") print(r) # 我今年18岁了, 你知道么, 18岁就已经很大了. 周杰伦18岁就得奖了
3.应用
import re
import requests
url = "https://gaze.run/"
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",
}
resp = requests.get(url)
obj = re.compile(r'.*?<h6 class="card-title text-truncate black-text">(?P<name>\w+)</h6>')
c = obj.finditer(resp.text)
for i in c:
print(i.group("name"))
二、bs4解析
1.css选择器
1. id选择器 #id值
2. 标签选择器 标签
3. 类选择器 .
4. 选择器分组 ,
5. 后代选择器 空格
6. 子选择器 父 > 子
7. 属性选择器 [属性=值]
2.bs4解析
-
安装
pip install bs4
-
查找
- find找一个,find_all找所有,代码中用法相同
find(标签, attrs={属性:值})
-
案例
import requests from bs4 import BeautifulSoup from urllib.parse import urljoin url = "https://desk.zol.com.cn/pc/" headers = { "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.82 Safari/537.36" } # 发送请求, 获取页面源代码 resp = requests.get(url, headers=headers) resp.encoding = 'gbk' # 设置一下字符集 # 1. 创建BeautifulSoup的对象 main_soup = BeautifulSoup(resp.text, "html.parser") # 2. 找到超链接, 请注意.这里面的属性拼接,多少会和页面稍微有一些细微的差别. a_list = main_soup.find("ul", attrs={"class": "pic-list2 clearfix"}).find_all("a") # 3. 循环出每一个超链接 for a in a_list: # 4.1 拿到href, 也就是子页面的url href = a.get("href") # 4.2 获取超链接中的文本信息 content = a.text print("没啥用,只是给你演示如何获取文本", content) # 5. 剔除特殊项 if href.endswith(".exe"): # 垃圾客户端. 坑我 continue # 6. 域名拼接 href = urljoin(url, href) # 7. 剩下的就是套娃了 child_resp = requests.get(href, headers=headers) child_resp.encoding = 'gbk' child_soup = BeautifulSoup(child_resp.text, "html.parser") # print(child_resp.text) # 适当的打印,可以帮助你调BUG img = child_soup.find("img", attrs={"id": "bigImg"}) img_src = img.get("src") # 下载图片 img_resp = requests.get(img_src, headers=headers) file_name = img_src.split("/")[-1] with open(file_name, mode="wb") as f: f.write(img_resp.content) print("下载完一张图片了")
三、xpath解析
3.1语法
-
测试用HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Title</title> </head> <body> <div> <p>一个很厉害的人</p> <ol> <li id="10086">周大强</li> <li id="10010">周芷若</li> <li class="joy">周杰伦</li> <li class="jolin">蔡依林</li> <ol> <li>阿信</li> <li>信</li> <li>信不信</li> </ol> </ol> </div> <hr /> <ul> <li><a href="http://www.baidu.com">百度</a></li> <li><a href="http://www.google.com">谷歌</a></li> <li><a href="http://www.sogou.com">搜狗</a></li> </ul> <ol> <li><a href="feiji">飞机</a></li> <li><a href="dapao">大炮</a></li> <li><a href="huoche">火车</a></li> </ol> <div class="job">李嘉诚</div> <div class="common">胡辣汤</div> </body> </html>
-
xpath解析1
from lxml import etree # 加载HTML f = open("xpath测试.html", mode='r', encoding='utf-8') page_source = f.read() # 和bs4一样, 把HTML交给etree hm = etree.HTML(page_source) # type:etree._Element # xpath各种用法 # 节点: 每个HTML标签叫节点 # 最外层节点: 根节点 # 内层节点: 子节点 # 父子节点: <爹><子></子></爹> html = hm.xpath("/html") # /根 print(html) # 看一眼标签名(测试用, 不用记住) body = hm.xpath("/html/body") # 第二个/表示子节点 print(body) # 接下来这句话请记住, xpath提取到的内容不论多少, 都会返回列表 p = hm.xpath("/html/body/div/p/text()") # 想要p里面的文本 print(p) # 列表 print(p[0]) # 要么取0. print("".join(p)) # 要么用join()进行合并. # 如果页面结构非常复杂. 这样一层一层数下来. 过年了 # xpath我们还可以用相对定位 p = hm.xpath("//p/text()") # // 表示在页面任意位置找 print(p) # 依然有效 # 我想找到 `周大强`, `周芷若`,`周杰伦`,`周大强`,`蔡依林` li = hm.xpath("//div/ol/li/text()") print(li) # 我想找到 `一个很厉害的人`后面ol中所有的文本 li = hm.xpath("//div/ol//text()") # 第二个//表示所有 # 请注意. 这里多了很多空白,一般我们提取一篇文章的时候,会用这种. # 结合字符串各种操作. 这些东西应该难不倒各位. print(li) print("".join(li).replace(" ", "").replace("\n", ""))
-
xpath解析2
from lxml import etree # 加载HTML f = open("xpath测试.html", mode='r', encoding='utf-8') page_source = f.read() # 和bs4一样, 把HTML交给etree hm = etree.HTML(page_source) # type:etree._Element # 重点:根据位置数元素 # 我想要`周芷若`, 分析角度: 它是ol里第二个li li = hm.xpath("//ol/li[2]/text()") print(li) # 这里莫名其妙带出了`信`, 请思考为什么? 请思考怎么干掉`信` # 我想单独找`信`聊聊 li = hm.xpath("//ol/ol/li[2]/text()") print(li) # 重点:根据属性筛选元素 # 我想要id=10086的li标签中的内容0 li = hm.xpath("//li[@id='10086']/text()") print(li) # 我想要class是joy的内容 li = hm.xpath("//*[@class='joy']/text()") print(li) # 我想要有class的li的内容 li = hm.xpath("//*[@class]/text()") print(li) # 我想和`啊信`,`信`,`信不信`单独聊聊 li_list = hm.xpath("//ol/ol/li") for li in li_list: print(li.xpath("./text()")) # ./表示当前节点, 也就是li # 提取`百度`, 谷歌, 搜狗的超链接href属性 li_list = hm.xpath("//ul/li") for li in li_list: print(li.xpath("./a/text()")) # ./表示当前节点, 也就是li print(li.xpath("./a/@href")) # @href 表示提取属性 # 我想要`火车` li = hm.xpath("//body/ol/li[last()]/a/text()") # last() 拿到最后一个 print(li) f.close()
3.2 案例
import requests
from lxml import etree
url = "http://www.boxofficecn.com/boxoffice2019"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.82 Safari/537.36"
}
resp = requests.get(url, headers=headers)
tree = etree.HTML(resp.text) # 加载页面源代码
# 提取数据
# 这个xpath不是随便写的. 你要找到你的`单条数据`的边界
trs = tree.xpath("//table/tbody/tr")[1:-1]
for tr in trs:
num = tr.xpath("./td[1]/text()") # 编号
year = tr.xpath("./td[2]//text()") # 年份
name = tr.xpath("./td[3]//text()") # 名称
money = tr.xpath("./td[4]/text()") # 票房
print(num, year, name, money)