2.数据解析

一、正则

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模块

  1. 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']
    
  2. search 匹配第一个结果,匹配不到返回none

    ret = re.search(r'\d', '5点之前. 你要给我5000万').group()
    print(ret) # 5
    
  3. match 从字符串开头匹配

    ret = re.match('a', 'abc').group()
    print(ret)     # a
    
  4. finditer 查找所有返回迭代器

    it = re.finditer("m", "mai le fo len, mai ni mei!")
    for el in it:
        print(el.group()) # 依然需要分组
    
  5. compile 预加载表达式

    obj = re.compile(r'\d{3}')  # 将正则表达式编译成为一个 正则表达式对象, 规则要匹配的是3个数字
    ret = obj.search('abc123eeee') # 正则表达式对象调用search, 参数为待匹配的字符串
    print(ret.group())  # 结果: 123
    
  6. 分组提取

    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"))  
    
  7. 正则替换

    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解析

  1. 安装

    pip install bs4
    
  2. 查找

    1. find找一个,find_all找所有,代码中用法相同
    2. find(标签, attrs={属性:值})
  3. 案例

    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语法

  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>
    
  2. 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", ""))
    
  3. 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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值