Python爬虫

python爬虫-分组(子表达式)与捕获

子表达式(分组)

在正则表达式中,通过一对圆括号起来的内容,我们就称之为'子表达式'

python 复制代码
import re

str = re.search(r'\d(\d)(\d)','xzczxdsa123eojvkv')
print(str)

输出结果:

注意:Python正则表达式前的r表示原生字符串(rawstring),该字符串声明了引用中的内容表达该内容的原始含义,避免了多次转义造成的反斜杠困扰。

正则表达式中\d\d\d中,(\d)(\d)就是子表达式,一共由两个()圆括号,则代表两个表达式

说明:findall方法,如果pattern中有分组则返回与分组匹配的列表,所以分组操作中不适合使用findall方法,建议使用search(匹配一个)或者finditer(匹配多个)方法。

2.捕获

当正则表达式在字符串中匹配到相应的内容后,计算机系统会自动把子表达式所匹配的内容放到系统的对应缓存区(缓存区送$1开始)

案例演示:

python 复制代码
import re

#定义一个字符串匹配字符串中的123,然后能单独获取2和3
str1 ='azxvzxca123ds'

#如果正则中带有分组(子表达式)数据,建议使用search方法或者finditer方法获取
result = re.search(r'\d(\d)(\d)',str1)

print(result.group())    # 匹配整体
print(result.group(1))   # 第1分组
print(result.group(2))   # 第2分组

输出结果:

python 复制代码
123
2
3

逐行讲解

  1. 正则 r'\d(\d)(\d)'
  • \d:匹配任意数字(这里捕获数字1没有括号,不属于分组
  • (\d)第 1 捕获组 ,匹配数字2
  • (\d)第 2 捕获组 ,匹配数字3
  1. group () 规则
  • result.group() / result.group(0) → 返回完整匹配内容123
  • result.group(1) → 返回第一个括号分组2
  • result.group(2) → 返回第二个括号分组3

关键知识点

  • re.search():扫描整个字符串,找到第一个匹配项 就停止(适合本例

    python 复制代码
    str1 = '12222abc'
    
    result =re.search(r'(\d)\1\1\1',str1)
    print(result.gr

  • re.match():只从字符串开头匹配,本例不能使用

  • 括号 () 作用:捕获分组,单独提取括号内匹配内容

  • 不带括号的匹配内容,无法单独提取,只能拿到整体匹配结果

反向引用(后向引用)

在正则表达式中,我们可以通过\n(n代表第n个缓存区的编号)来引用缓存区中的内容,我们把这个过程就称之为'反向引用'

① 连续 4 个数字 re.search (r'\d\d\d\d', str1)

1234、5678、6789

② 连续的 4 个数字,但是数字的格式为 1111、2222、3333、4444、5555 效果?

re.search (r'(\d)\1\1\1', str1)

示例:

python 复制代码
import  re



str1 = '12222abc'

result =re.search(r'(\d)\1\1\1',str1)
print(result.group())

输出结果:

代码分析:

  1. 正则 r'(\d)\1\1\1'
    • (\d):捕获任意 1 个数字,存入分组 1
    • \1反向引用,代表必须和分组 1 捕获到的字符完全相同
    • 整体含义:匹配连续 4 个一模一样的数字
  2. 字符串 12222abc
    • 字符序列:12222
    • 2222 满足连续 4 个相同数字,匹配成功
  3. re.search() 从左向右扫描字符串,找到第一个符合条件的子串。

💡 如果想匹配至少 4 个相同数字,可以改成量词写法:

复制代码
result =re.search(r'(\d)\1{3,}',str1)

\1{3,} 代表:分组 1 的数字重复 3 次及以上,加上前面 1 个,总长度≥4。

正则表达式其他方法

1.选择匹配符

可以匹配多个规则

案例:匹配字符串hellojava或者hellopython

python 复制代码
str = 'hellojava , hellopython'
result = re.finditer(r'hello(java|python)',str)
if result:
    for i in result:
        print(i.group())
else:
    print('匹配失败')

输出结果:

代码分析:

1. 正则表达式拆解 hello(java|python)

  • hello:精准匹配字面字符串 hello
  • (java|python):分组 + 多选分支
    • | 代表或者
    • 含义:匹配 java 或者 python
  • 整体规则:匹配 hellojava 或者 hellopython

2. 方法说明 re.finditer()

  • 返回迭代器对象,保存所有匹配成功的结果(不是列表)
  • 需要用 for 循环遍历取出每一个匹配对象
  • re.findall() 区别:
    • findall:直接返回匹配字符串列表
    • finditer:返回匹配对象,可以使用 .group(1) 获取分组内容

2.分组别名

python 复制代码
import re
str_data = '<book>python</book>'
# 正确正则写法
result = re.search(r'<(?P<mark>\w+)>\w+<\/(?P=mark)>', str_data)
print(result.group())

输出结果:

正则拆分 r'<(?P<mark>\w+)>\w+<\/(?P=mark)>'

  1. (?P<mark>\w+)
    • (?P<名称>表达式)命名捕获分组
    • 把标签名 book 捕获,分组别名叫做 mark
  2. (?P=mark)
    • 命名反向引用
    • 代表:和名为mark分组捕获到的内容完全一致
    • 作用:保证开始标签和闭合标签名称相同<book>...</book>,不会匹配 <book>...</page>
  3. 其余部分
    • < > </:匹配标签符号
    • \w+:匹配标签中间的文本(python)

综合案例:

需求:在列表中'apple', 'banana', 'orange', 'pear', 'watermelon'匹配apple

python 复制代码
import  re



list1 = ['apple', 'banana', 'orange', 'pear', 'watermelon']
str1 = str(list1)
result = re.finditer('(apple)',str1)
if result:
    for i in result:
        print(i.group())
else:
    print('匹配失败')

输出结果:

代码分析:

  • str(list1) 列表转为字符串,内部元素变成带引号的文本,字符串中包含子串apple,所以可以匹配成功。

  • 正则 (apple) 括号创建捕获分组,这里分组没有实际业务作用,等价于直接写apple; 可以通过i.group(1)取出分组内容。

  • 重要提醒(老生常谈) re.finditer() 返回迭代器对象,永远不为 None 。 哪怕没有匹配内容,result依旧是迭代器,if result:判断恒成立。 👉 如果匹配不到内容,for循环不会执行,不会进入else分支!2.需求:怕匹配出163、126、qq等邮箱

Python简单爬虫实践案例

学习目标

基于FastAPI之Web站点开发

1.基于FastAPI搭建Web服务器

python 复制代码
#导入FastAPI
from fastapi import  FastAPI
#导入响应Respons模块
from fastapi import  Response
#导入服务器uvicorn模块
import uvicorn


#创建一个FastAPI实例对象
app = FastAPI()
#通过@app路由装饰器收发数据
#@app.get(参数):按照get方法接收请求参数
#请求资源的url
@app.get("index.html")
def main():
    with open('source/index.html') as f:
        data = f.read()
    return Response(data, media_type="text/html")
#启动服务器
uvicorn.run(app, host="127.0.0.1", port=8000)

web服务器和游览器的通讯流程

实际上web服务器和浏览器的通讯流程过程并不是一次性完成的,这里HTML代码中也会有访问服务器的代码,比如请求图片资源。

python爬虫

介绍

爬虫的基本步骤:

基本步骤:

1.起始url地址

2.发出请求获取响应数据

3.对响应数据解析

4.数据入库

安装requests模块

requests:可以模拟游览器请求

打开命令行工具(Windows的CMD/PowerShell或macOS/Linux的终端),输入以下命令:

如果使用的是Python 3,可能需要明确指定pip版本:

bash 复制代码
pip3 install requests
 

对于使用Anaconda的用户,可以通过conda命令安装:

bash 复制代码
conda install requests
 

使用requests模拟浏览器请求

安装完成后,可以通过requests模块发送HTTP请求。以下是一个简单的GET请求示例,模拟浏览器访问网页:

python 复制代码
import requests

# 设置请求头,模拟浏览器
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}

response = requests.get('https://www.example.com', headers=headers)
print(response.text)  # 输出网页内容
 

如果需要发送POST请求,可以这样操作:

python 复制代码
data = {'key1': 'value1', 'key2': 'value2'}
response = requests.post('https://httpbin.org/post', data=data, headers=headers)
print(response.json())  # 输出JSON响应
 

用爬虫爬取网页图片的信息

访问百度的首页资源,在控制台可以看见照片都是以.png结尾

点击第一个现实请求的URL是https://pss.bdstatic.com/static/superman/img/topnav/newfanyi-da0cea8f7e.png,正真的图片获取地址,爬取图片就是通过图片url保存在本地

爬取照片的步骤

1.获取html代码

2.解析html代码获取图片URL

3.通过图片url获取图片

获取html代码

python 复制代码
import requests
data = requests.get('https://www.baidu.com')

data = data.content.decode('utf-8')
print(dat

输出结果:

html 复制代码
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');
                </script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>

使用open方法通过图片url获取图片

python 复制代码
import requests


data = requests.get('https://pss.bdstatic.com/static/superman/img/topnav/newfanyi-da0cea8f7e.png')
#图片不需要解码
getpic = data.content

#使用with创建一个本地文件
with open('source/newfanyi.png','wb') as f:
    f.write(getpic)

输出结果:

代码分析:

  1. 导入第三方网络请求库 requests,用于发送 HTTP 请求,获取网络资源。

    data = requests.get('https://pss.bdstatic.com/static/superman/img/topnav/newfanyi-da0cea8f7e.png')

  2. 发送 GET 请求 ,访问图片 URL;

    • 返回的 data 不是图片本身 ,是一个 Response 响应对象;
    • 对象内部包含响应状态码、响应头、图片二进制数据等信息。

    getpic = data.content

  3. data.content:获取原始二进制字节数据

重点区分:

  • .content:原始 bytes,图片、音视频、压缩包必须使用
  • .text:自动编码转为字符串,仅用于网页文本,图片使用会损坏文件
复制代码
with open('source/newfanyi.png','wb') as f:
    f.write(getpic)
  1. with open(...):上下文管理器打开文件,代码执行结束自动关闭文件 ,不需要手动 f.close()
    • 打开模式 wb:write binary
      • w:覆盖写入;b:二进制模式
      • 二进制模式不会自动处理编码换行,保存图片必备
  2. f.write(getpic):把图片二进制字节写入本地文件,完成保存。

解析html代码获取图片URL

python 复制代码
html = resp.text

# 解析网页
soup = BeautifulSoup(html, "html.parser")
# 找到页面所有<img>标签
img_tags = soup.find_all("img")

img_url_list = []
for img in img_tags:
    src = img.get("src")
    if not src:
        continue
    # 补全url
    if src.startswith("//"):
        full_src = "https:" + src
    elif src.startswith("/"):
        full_src = "https://www.baidu.com" + src
    else:
        full_src = src

    img_url_list.append(full_src)
    print("图片链接:", full_src)

print(f"\n一共找到 {len(img_url_list)} 张图片")

输出结果:、

代码分析:

  1. BeautifulSoup(html, "html.parser")
    • 作用:把杂乱的文本格式 HTML 字符串,转换成结构化文档对象(DOM 树)
    • 第一个参数:原始网页文本
    • 第二个参数:解析器,html.parser 是 Python 内置解析器,无需额外安装
  2. soup 对象:可以使用专门方法快速查找标签,代替手写 split() / find() 字符串切割

python

运行

复制代码
# 找到页面所有<img>标签
img_tags = soup.find_all("img")
  • find_all("img")查找页面中全部 <img> 标签
  • 返回值:列表,列表内每一个元素都是一个图片标签对象

对比手写字符串截取:不用逐行遍历、不用处理换行,一行找到所有图片标签

python

运行

复制代码
img_url_list = []

创建空列表,用来存放处理完成的完整图片链接,方便后续统一遍历下载

python

运行

复制代码
for img in img_tags:
    src = img.get("src")
    if not src:
        continue
  1. 循环遍历每一个图片标签对象
  2. img.get("src"):获取标签里 src 属性的值(图片地址) ✅ 推荐使用 .get();不推荐 img['src']
    • 如果标签缺少 src 属性img['src'] 会直接报错崩溃
    • .get("src") 找不到属性会返回 None,程序不会崩溃
  3. if not src: continue 判断:如果 src 是空 / None,直接跳过当前循环,不处理无效图片

完整demo:

python 复制代码
import requests
from bs4 import BeautifulSoup
import os

# 目标网址
url = "https://www.baidu.com"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36"
}

resp = requests.get(url, headers=headers)
resp.encoding = "utf-8"
html = resp.text

# 解析网页
soup = BeautifulSoup(html, "html.parser")
# 找到页面所有<img>标签
img_tags = soup.find_all("img")

img_url_list = []
for img in img_tags:
    src = img.get("src")
    if not src:
        continue
    # 补全url
    if src.startswith("//"):
        full_src = "https:" + src
    elif src.startswith("/"):
        full_src = "https://www.baidu.com" + src
    else:
        full_src = src

    img_url_list.append(full_src)
    print("图片链接:", full_src)

print(f"\n一共找到 {len(img_url_list)} 张图片")

# ============可选:批量全部下载============
os.makedirs("baidu_img", exist_ok=True)
for idx, pic_url in enumerate(img_url_list):
    try:
        pic_resp = requests.get(pic_url, headers=headers, timeout=10)
        save_path = f"baidu_img/pic_{idx}.png"
        with open(save_path, "wb") as f:
            f.write(pic_resp.content)
        print(f"已下载:{pic_url} → {save_path}")
    except Exception as e:
        print(f"下载失败 {pic_url},原因:{e}")

多任务爬虫实现

为什么要使用多任务爬取数据

在真正的工作环境中,我们爬取的数据可能非常的多,如果还是使用单任务实现,这时候就会让我们爬取数据的时间很长,那么显然使用多任务可以大大提升我们爬取数据的效率

多任务代码实现

具体爬取实现:

python 复制代码
import requests
from bs4 import BeautifulSoup
import os
import multiprocessing

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36"
}

# 获取图片函数(交给子进程执行)
def get_pic():
    url = "https://www.baidu.com"
    resp = requests.get(url, headers=headers)
    resp.encoding = "utf-8"
    html = resp.text

    soup = BeautifulSoup(html, "html.parser")
    img_tags = soup.find_all("img")

    img_url_list = []
    for img in img_tags:
        src = img.get("src")
        if not src:
            continue
        # 补全url
        if src.startswith("//"):
            full_src = "https:" + src
        elif src.startswith("/"):
            full_src = "https://www.baidu.com" + src
        else:
            full_src = src
        img_url_list.append(full_src)
        print("图片链接:", full_src)

    print(f"\n一共找到 {len(img_url_list)} 张图片")

    # 批量下载
    os.makedirs("baidu_img", exist_ok=True)
    for idx, pic_url in enumerate(img_url_list):
        try:
            pic_resp = requests.get(pic_url, headers=headers, timeout=10)
            save_path = f"baidu_img/pic_{idx}.png"
            with open(save_path, "wb") as f:
                f.write(pic_resp.content)
            print(f"已下载:{pic_url} → {save_path}")
        except Exception as e:
            print(f"下载失败 {pic_url},原因:{e}")


if __name__ == '__main__':
    # 创建进程 target=函数名,不加括号!
    p1 = multiprocessing.Process(target=get_pic)
    # 启动进程
    p1.start()
    # 等待子进程执行完毕(可选)
    p1.join()
相关推荐
进制树31 分钟前
【飞控开发实战·⑲】ROS2无人机开发环境搭建:Jazzy安装、工作空间与hello_drone节点实战
开发语言·安全·无人机·课程设计
zzzzzz3101 小时前
AI 助手最危险的不是报错,而是“看起来成功”:我给工作流加了四道保险
人工智能·python
牛马也想出海1 小时前
亚马逊爬虫代理IP:IP类型选择与配置指南
开发语言·php
用户8356290780511 小时前
如何使用 Python 将 PowerPoint 转换为 PDF 文档
后端·python
菜冻鱼1 小时前
Python-pytorch-高级技巧
开发语言·人工智能·pytorch·python·深度学习·神经网络·聚类
lpfasd1231 小时前
python webview打包版卡死、开发版正常
开发语言·python
用户8356290780511 小时前
如何使用 Python 为 PowerPoint 幻灯片添加切换效果
后端·python
weixin_461408581 小时前
npm npx yarn
开发语言·前端·javascript
菜冻鱼1 小时前
Python-pytorch-模型保存与加载
开发语言·人工智能·pytorch·python·深度学习·机器学习
骇客野人2 小时前
Java SSO 统一认证方案
java·开发语言