最新资讯

  • Python爬虫入门实战指南

Python爬虫入门实战指南

2026-01-30 06:26:38 栏目:最新资讯 4 阅读

1. requests 模块

1.1. 处理 get 请求
import requests

content = input('请输入你要检索的内容:')
url = f"https://www.sogou.com/web?query={content}"
headers = {
    # 添加一个请求头信息 UA
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36"
}
response = requests.get(url, headers=headers)
print(response.text)
1.2. 处理 post 请求
import requests

url = "https://fanyi.baidu.com/sug"

data = {
    "kw": input("请输入一个单词")
}

resp = requests.post(url, data=data)
resp.encoding = "utf-8"

# 此时拿到的是文本字符串
print(resp.text)
# 此时拿到的是 json 数据
print(resp.json())
1.3. 多参数 get 请求
import requests

url = "https://movie.douban.com/j/chart/top_list"

data = {
    "type": "13",
    "interval_id": "100:90",
    "action": "",
    "start": "0",
    "limit": "20"
}

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0"
}

resp = requests.get(url, params=data, headers=headers)
# print(resp.text)
print(resp.json())
print(resp.request.url)

2. 正则表达式

2.1. 元字符

2.2. 量词

控制前面元字符出现的次数

2.3. 贪婪匹配 | 惰性匹配

3. 数据解析方式

3.1. re 解析
3.1.1. 基本使用
import re

result = re.findall("a", "我是一个abcdefga")
print(result)
# 输出:['a', 'a']


result = re.findall(r"d+", "我今年18岁,我有20000000块")
print(result)
# 输出:['18', '20000000']


result = re.finditer(r"d+", "我今年18岁,我有20000000块")
for item in result:  # 从迭代器中拿到内容
    print(item.group())  # 从匹配到的结果中拿到数据
# 输出:
# 18
# 20000000


# search 只会匹配到第一次匹配的内容
result = re.search(r"d+", "我叫周杰伦,今年32岁,我的班级是3年2班")
print(result.group())
# 输出:32


# match 在匹配的时候,是从字符串的开头进行匹配的,类似在正则前面加上了^
result = re.match(r"d+", "我叫周杰伦,今年32岁,我的班级是3年2班")
print(result)
3.1.2. 预加载

提前加载正则对象

# 预加载
# 提前把正则对象加载完毕
obj = re.compile(r"d+")
# 直接把加载好的正则进行使用
result = obj.findall("我叫周杰伦,今年32岁,我的班级是3年2班")
print(result)
3.1.3. 提取分组数据
# 提取分组数据
# (?P<名字>正则)
# 提取数据的时候,需要group("名字")
s = """
中国联通>
中国移动>
"""
obj01 = re.compile(r".*?") obj02 = re.compile(r"(.*?)") obj03 = re.compile(r"(?P.*?)") result01 = obj01.findall(s) result02 = obj02.findall(s) result03 = obj03.finditer(s) print(result01) print(result02) for item in result03: id = item.group("id") name = item.group("name") print(id) print(name)
3.1.4. 实操案例

爬取豆瓣 top250 电影信息

import csv
import re

import requests

# 使用with语句自动管理文件,结合csv.writer写入数据
# newline='' 避免写入时出现空行(Windows系统)
with open("top250.csv", mode="a+", encoding='utf-8-sig', newline='') as f:
    # 创建csv写入对象
    csv_writer = csv.writer(f)
    # 移动文件指针到开头,判断是否为空文件(为空则写入表头)
    f.seek(0)
    if not f.readline():
        csv_writer.writerow(["电影名称", "导演", "上映年份", "评分", "评价人数"])
    for start in range(0, 250, 25):
        url = f"https://movie.douban.com/top250?start={start}&filter="
        headers = {
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0",
            "Referer": "https://movie.douban.com/",  # 模拟从豆瓣主页跳转,提升兼容性
        }

        try:
            resp = requests.get(url, headers=headers, timeout=10)
            if resp.status_code != 200:
                print(f"第 {start // 25 + 1} 页请求失败!状态码:{resp.status_code}")
                continue
            resp.encoding = "utf-8"
            pageSource = resp.text

            # 正则表达式(保留你的原有逻辑)
            obj = re.compile(
                r'
.*?' r'(?P.*?).*?' r'

.*?导演: (?P.*?).*?' r'
(?P.*?).*?'
r'(?P.*?).*?' r'(?P.*?)人评价', re.S ) # 正则匹配并写入数据 result = obj.finditer(pageSource) count = 0 # 统计当前页爬取到的电影数 for item in result: data = item.groupdict() # 转为字典,方便处理 # 清洗数据(去除空格、多余字符) data["name"] = data["name"].strip() data["dao"] = data["dao"].strip() data["year"] = data["year"].strip() data["score"] = data["score"].strip() data["num"] = data["num"].strip() # 写入 CSV csv_writer.writerow([data["name"], data["dao"], data["year"], data["score"], data["num"]]) count += 1 print(f"第 {start // 25 + 1} 页爬取完成,共 {count} 部电影") except Exception as e: print(f"第 {start // 25 + 1} 页爬取失败!错误信息:{str(e)}") print("数据写入完成!")

爬取电影天堂电影信息

"""
1.提取到主页面中的每一个电影背后的url地址
1.1.拿到"2026必看热片"的HTML代码
1.2.从HTML代码中提取href值

2.访问子页面,提取电影的名称以及下载地址
2.1.拿到子页面源代码
2.2.数据提取
"""
import csv
import re
import requests

with open("2026必看热片.csv", mode="a+", encoding='utf-8-sig', newline='') as f:
    # 创建csv写入对象
    csv_writer = csv.writer(f)
    # 移动文件指针到开头,判断是否为空文件(为空则写入表头)
    f.seek(0)
    if not f.readline():
        csv_writer.writerow(["片名", "下载链接"])

    url = "https://www.dytt8899.com/"
    headers = {
        "referer": "https://www.dytt8899.com/",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0"
    }
    try:
        resp = requests.get(url, headers=headers, timeout=10)
        resp.encoding = "gbk"

        # 1.提取2026必看热片部分的HTML代码
        obj01 = re.compile(r'2026必看热片.*?
    (?P.*?)
'
, re.S) result01 = obj01.search(resp.text) html = result01.group('html') # 2.提取a标签中的href值 obj02 = re.compile(r"
  • .*?)' title") result02 = obj02.finditer(html) obj03 = re.compile(r'
    .*?◎片  名(?P.*?)
    .*?' r'.*?)">', re.S) count = 0 for item in result02: # 拼接子页面的url child_url = url.strip('/') + item.group('href').strip() child_resp = requests.get(child_url) child_resp.encoding = 'gbk' result03 = obj03.search(child_resp.text) # 清洗数据 movie = result03.group('movie').strip() download = result03.group('download').strip() csv_writer.writerow([movie, download]) count += 1 print(f"第 {count} 条数据爬取完成") except Exception as e: print(f"电影数据爬取失败,错误信息:{str(e)}") print("数据写入完成")
  • 3.2. bs4 解析
    3.2.1. 基本使用
    from bs4 import BeautifulSoup
    
    html = """
    
    • 张无忌
    • 周星驰
    • 猪八戒
    • 武则天
    """
    # 1.初始化BeautifulSoup对象 page = BeautifulSoup(html, "html.parser") # page.find("标签名", attrs={"属性": "值"}) # 查找某个元素,只会找到一个结果 # page.find_all("标签名", attrs={"属性": "值"}) # 找到一堆结果 li = page.find("li", attrs={"id": "abc"}) print(li) # 输出:
  • 周星驰
  • a = li.find("a") print(a) # 输出: 周星驰 print(a.text) # 输出: 周星驰 print(a.get("href")) # 输出: zxc.com li_list = page.find_all("li") for li in li_list: a = li.find("a") text = a.text href = a.get("href") print(text, href)
    3.2.2. 实操案例

    Boss 直聘热门职位

    import csv
    
    import requests
    import urllib3
    from bs4 import BeautifulSoup
    
    with open("热门职位.csv", mode="a+", encoding='utf-8-sig', newline='') as f:
        # 创建csv写入对象
        csv_writer = csv.writer(f)
        # 移动文件指针到开头,判断是否为空文件(为空则写入表头)
        f.seek(0)
        if not f.readline():
            csv_writer.writerow(["职位", "薪酬", "描述"])
        url = "https://www.zhipin.com/?ka=header-home-logo"
        headers = {
            "Referer": "https://www.zhipin.com/",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0"
        }
        # 抑制SSL警告(可选,避免控制台输出无关警告)
        urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
        try:
            resp = requests.get(url, headers=headers, timeout=10, verify=False)
            resp.encoding = "utf-8"
            # 初始化BS4对象
            page = BeautifulSoup(resp.text, "html.parser")
            hot_job = page.find("div", attrs={"class": "hot-job-box"})
            job_list = hot_job.find_all("div", attrs={"class": "sub-li"})
            for job in job_list:
                name = job.find("p", attrs={"class": "name"}).text
                salary = job.find("p", attrs={"class": "salary"}).text
                job_text = job.find("p", attrs={"class": "job-text"})
                desc_text = ""
                if job_text:  # 先判断job-text标签是否存在
                    desc_spans = job_text.find_all("span")
                    # 用列表推导式拼接,避免循环中重复赋值的问题
                    desc_list = [span.text.strip() for span in desc_spans if span.text.strip()]
                    desc_text = ",".join(desc_list)  # 更高效的拼接方式
                csv_writer.writerow([name, salary, desc_text])
                print(f"已写入:职位={name},薪酬={salary},描述={desc_text}")
        except Exception as e:
            print(f"职位数据爬取失败,错误信息:{str(e)}")
    print("数据写入完成")
    
    3.3. xpath 解析

    XPath 是一门在 XML 文档中查找信息的语言。

    3.3.1. 基本使用
    from lxml import etree
    
    # xpath处理XML
    xml = """
    
        吉多·范罗苏姆
        
            Python编程:从入门到实践
            埃里克·马瑟斯
            89.00
            2020-07-01
        
        
        
            Java核心技术
            凯·S·霍斯特曼
            128.00
            2019-11-01
        
    
    """
    
    et = etree.XML(xml)
    result01 = et.xpath("/library")  # 表示根节点
    result02 = et.xpath("/library/book/title/text()")[0]  # 得到子节点, text() 拿文本
    result03 = et.xpath("/library/*/author/text()")  # * 通配符,表示谁都行
    result04 = et.xpath("/library/*/author[@class='kai']/text()")  # [] 表示属性筛选,@属性名=值
    result05 = et.xpath("/library/book/@id")  # @属性,可以直接拿到属性值
    print(result01)
    print(result02)
    print(result03)
    print(result04)
    print(result05)
    
    # xpath处理HTML
    html = """
    
    
    
        
        Title
    
    
        
    • 百度
    • 谷歌
    • 搜狗
    1. 飞机
    2. 大炮
    3. 火车
    李嘉诚
    胡辣汤
    """
    et = etree.XML(html) li_list01 = et.xpath("/html/body/ul/li[2]/a/text()") li_list02 = et.xpath("//li") print(li_list01) for li in li_list02: href = li.xpath("./a/@href")[0] # ./表示当前节点 text = li.xpath("./a/text()")[0] # ./表示当前节点 print(href, text)
    3.3.2. 实操案例
    import csv
    
    import requests
    import urllib3
    from lxml import etree
    
    # 抑制SSL警告(可选,避免控制台输出无关警告)
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    DOMAIN_URL = "https://www.bilibili.com/video/"
    CSV_FILE_PATH = "B站热搜.csv"
    TARGET_URL = "https://www.remenla.com/hot/bilibili"
    HEADERS = {
        "Referer": "https://www.remenla.com/hot/zhihu",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0"
    }
    
    
    def extract_bv_from_url(url: str) -> str | None:
        """
        从URL中提取BV号(适用于BV号在最后一个/之后的情况)
        """
        # 按/分割字符串,取最后一部分
        bv_code = url.split('/')[-1]
        # 简单校验:确保提取的内容以BV开头
        if bv_code.startswith('BV'):
            return DOMAIN_URL + bv_code
        else:
            return None
    
    
    def main():
        with open(CSV_FILE_PATH, mode="a+", encoding='utf-8-sig', newline='') as f:
            # 创建csv写入对象
            csv_writer = csv.writer(f)
            # 移动文件指针到开头,判断是否为空文件(为空则写入表头)
            f.seek(0)
            if not f.readline():
                csv_writer.writerow(["标题", "描述", "链接", "热度"])
    
            try:
                resp = requests.get(TARGET_URL, headers=HEADERS, timeout=10, verify=False)
                resp.raise_for_status()
                resp.encoding = "utf-8"
    
                et = etree.HTML(resp.text)
                content_list = et.xpath("//div[@class='list-container']//div[@class='list-content']")
                if not content_list:
                    raise Exception("未匹配到任何热搜条目,请检查XPath路径是否正确")
                for content in content_list:
                    item_data = {
                        "title": "",  # 标题
                        "desc": "",  # 目标描述文本(可能为空)
                        "bv_url": "",  # BV号链接
                        "hot_value": ""  # 热度值
                    }
                    item_data["title"] = content.xpath(".//a/text()")[0].strip()
                    href = content.xpath(".//a/@href")[0].strip()
                    item_data["bv_url"] = extract_bv_from_url(href)
                    item_data["hot_value"] = content.xpath("//span/text()")[0].strip()
                    div_list = content.xpath('.//div')
                    for div in div_list:
                        # 检查当前div是否是热度div(包含icon-fire或format-number)
                        is_hot_div = bool(
                            div.xpath('./i[@class="iconfont icon-fire"]') or div.xpath('./span[@class="format-number"]'))
                        if not is_hot_div:
                            # 不是热度div,提取文本并清理
                            raw_text = div.xpath('./text()')[0].strip()
                            # 排除只有"-"的无效文本
                            if raw_text and raw_text != "-":
                                item_data["desc"] = raw_text
                                break  # 找到有效描述就停止遍历
                    csv_row = [
                        item_data["title"],
                        item_data["desc"],
                        item_data["bv_url"],
                        item_data["hot_value"]
                    ]
                    csv_writer.writerow(csv_row)
            except Exception as e:
                print(f"热搜数据爬取失败,错误信息:{str(e)}")
    
    
    if __name__ == "__main__":
        main()
    
    3.4. pyquery 解析
    3.4.1. 基本使用
    from pyquery import PyQuery
    
    html = """
    
    • 谷歌
    • 百度
    • 腾讯
    """
    # 加载html内容 p = PyQuery(html) a_list = p("a") a = p("a").eq(0) print(a_list) print(a) print("- - - - - - " * 10) # 链式操作 a = p("ul")("li")("a") a = p("ul li a") print(a) print("- - - - - - " * 10) a = p(".aaa a") # class="aaa" print(a) print("- - - - - - " * 10) a = p("#qq a") # id="qq" print(a) print("- - - - - - " * 10) href = p("#qq a").attr("href") text = p("#qq a").text() print(text, href) print("- - - - - - " * 10) # 多个标签拿属性 it = p("ul li a").items() for item in it: href = item.attr("href") text = item.text() print(text, href) """ 快速总结: 1. pyquery(选择器) 2. items() 当选择器选择的内容很多,需要一个一个处理时 3. attr(属性名) 获取属性信息 4. text() 获取文本 """
    3.4.2. 进阶使用
    from pyquery import PyQuery
    
    html = """
    
        
    哒哒哒
    嘟嘟嘟
    """
    # 加载html内容 p = PyQuery(html) # 在xxxx标签后面添加xxxxx新标签 p("div.aaa").after("""
    吼吼吼
    """
    ) p("div.aaa").append("""嘿嘿嘿""") p("div.bbb").attr("class", "aaa") # 修改/新增属性 p("div.ccc").attr("id", "12306") p("div.ccc").remove_attr("id") # 删除属性 p("div.ccc").remove() # 删除标签
    3.4.3. 实操案例
    
    import csv
    
    import requests
    import urllib3
    from pyquery import PyQuery
    
    # 抑制SSL警告(可选,避免控制台输出无关警告)
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    CSV_FILE_PATH = "抖音热搜.csv"
    TARGET_URL = "https://www.zhuanti.com.cn/top/z46"
    HEADERS = {
        "Referer": "https://m.zhuanti.com.cn/",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0"
    }
    
    
    def get_page_source(url: str) -> str | None:
        resp = requests.get(url, headers=HEADERS, timeout=10, verify=False)
        resp.raise_for_status()
        resp.encoding = "utf-8"
        return resp.text
    
    
    def parse_page_source(html: str) -> None:
        with open(CSV_FILE_PATH, mode="a+", encoding='utf-8-sig', newline='') as f:
            # 创建csv写入对象
            csv_writer = csv.writer(f)
            # 移动文件指针到开头,判断是否为空文件(为空则写入表头)
            f.seek(0)
            if not f.readline():
                csv_writer.writerow(["排名", "标题", "链接", "热度"])
            doc = PyQuery(html)
            item_list = doc(".item").items()
            for item in item_list:
                rank = item(".rank").text()
                title = item(".titles").text()
                href = item(".titles a").attr("href")
                reading = item(".reading").text()
                csv_writer.writerow([rank, title, href, reading])
    
    
    def main():
        try:
            html = get_page_source(TARGET_URL)
            parse_page_source(html)
        except Exception as e:
            print(f"热搜数据爬取失败,错误信息:{str(e)}")
    
    
    if __name__ == "__main__":
        main()
    

    4. 模拟浏览器登录

    import requests
    
    # 会话
    session = requests.session()
    headers = {
        "Content-Type": "application/json",
        "Referer": "http://47.113.113.212/",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0"
    }
    data = {
        "username": "albert",
        "password": "123456"
    }
    
    # 登录
    url = "http://47.113.113.212:8080/auth/login"
    login_resp = session.post(url, json=data, timeout=10, headers=headers)
    login_resp.raise_for_status()
    login_resp.encoding = "utf-8"
    token = login_resp.headers["Authorization"]
    
    # 请求
    headers = {
        "Authorization": token
    }
    resp = session.get("http://47.113.113.212:8080/auth/me", timeout=10, headers=headers)
    resp.raise_for_status()
    print(resp.json().get("data"))
    

    5. 防盗链

    import requests
    import urllib3
    
    url = "https://www.pearvideo.com/video_1804596"
    contId = url.split("_")[1]
    
    videoStatusUrl = f"https://www.pearvideo.com/videoStatus.jsp?contId={contId}&mrd=0.5587364561383386"
    
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0",
        # 防盗链:溯源,当前请求的上一级
        "Referer": "https://www.pearvideo.com/video_1804596",
    }
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    resp = requests.get(videoStatusUrl, headers=headers, timeout=10, verify=False)
    dic = resp.json()
    srcUrl = dic["videoInfo"]["videos"]["srcUrl"]
    systemTime = dic["systemTime"]
    srcUrl = srcUrl.replace(systemTime, f"cont-{contId}")
    
    with open("a.mp4", mode="wb") as f:
        f.write(requests.get(srcUrl, timeout=10, verify=False).content)
    

    6. 代理

    import requests
    
    url = "https://www.baidu.com/"
    
    # 准备代理信息
    proxy={
        "http": "http://218.207.102.106:843",
        "https": "https://218.207.102.106:843"
    }
    
    # proxies代理
    resp = requests.get(url, proxies=proxy)
    resp.encoding = "utf-8"
    print(resp.text)
    

    7. 多线程

    # 线程,进程
    # 进程是资源单位,每一个进程至少要有一个线程
    # 线程是执行单位
    
    
    # 单线程
    # def func():
    #     for i in range(1000):
    #         print("func", i)
    #
    #
    # if __name__ == '__main__':
    #     func()
    #     for i in range(1000):
    #         print("main", i)
    
    
    # 多线程(写法一)
    from threading import Thread
    
    
    def func(name):
        for i in range(1000):
            print(name, i)
    
    
    if __name__ == '__main__':
        t1 = Thread(target=func, args=("aaa",))  # 创建线程并给线程安排任务
        t1.start()  # 多线程状态为可以开始工作状态,具体的执行时间由CPU决定
        t2 = Thread(target=func, args=("bbb",))
        t2.start()
        for i in range(1000):
            print("main", i)
    
    
    # 多线程(写法二)
    # class MyThread(Thread):
    #     def run(self): # 固定的 -> 当线程被执行时,被执行的就是run()
    #         for i in range(1000):
    #             print("子线程", i)
    #
    #
    # if __name__ == '__main__':
    #     t1 = MyThread()
    #     t1.start() # 开启线程
    #     t2 = MyThread()
    #     t2.start() # 开启线程
    #
    #     for i in range(1000):
    #         print("主线程", i)
    

    8. 多进程

    from multiprocessing import Process
    
    
    def func():
        for i in range(1000):
            print("子进程", i)
    
    
    if __name__ == '__main__':
        p = Process(target=func)
        p.start()
        for i in range(1000):
            print("主进程", i)
    

    9. 线程池 | 进程池

    # 线程池:一次性开辟一些线程,用户直接给线程池提交任务,线程任务的调度交给线程池来完成
    from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
    
    
    # 任务函数
    def fn(name):
        # 循环10次
        for i in range(10):
            print(name, i)
    
    
    if __name__ == '__main__':
        # 创建线程池
        with ThreadPoolExecutor(max_workers=50) as t:
            for i in range(100):
                # submit方法:提交任务到线程池,非阻塞(主程序继续执行下一次循环)
                t.submit(fn, name=f"线程{i}")
        # 等待线程池中的任务全部执行完毕,才继续执行(守护)
        print("123")
    
        # 创建进程池
        with ProcessPoolExecutor(max_workers=50) as t:
            for i in range(100):
                t.submit(fn, name=f"进程{i}")
        # 等待进程池中的任务全部执行完毕,才继续执行(守护)
        print("123")
    
    9.1. 实操案例
    import csv
    from concurrent.futures import ThreadPoolExecutor
    
    import requests
    import urllib3
    from pyquery import PyQuery
    
    # 抑制SSL警告(可选,避免控制台输出无关警告)
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    CSV_FILE_PATH = "豆瓣影评.csv"
    HEADERS = {
        "Referer": "https://movie.douban.com/chart",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0"
    }
    
    
    def get_page_source(url: str) -> str | None:
        resp = requests.get(url, headers=HEADERS, timeout=10, verify=False)
        resp.raise_for_status()
        resp.encoding = "utf-8"
        return resp.text
    
    
    def parse_page_source(html: str) -> None:
        with open(CSV_FILE_PATH, mode="a+", encoding='utf-8-sig', newline='') as f:
            # 创建csv写入对象
            csv_writer = csv.writer(f)
            # 移动文件指针到开头,判断是否为空文件(为空则写入表头)
            f.seek(0)
            if not f.readline():
                csv_writer.writerow(["影片名称", "用户", "标题", "链接", "内容", "点赞", "评论", "发布时间"])
            doc = PyQuery(html)
            item_list = doc(".main.review-item").items()
            for item in item_list:
                movie_title = item(".subject-img img").attr("title")
                name = item(".name").text()
                title = item(".main-bd h2 a").text()
                href = item(".main-bd h2 a").attr("href")
                content = item(".short-content").text().strip()
                up = item(".action a.up").text()
                comment = item(".action a.reply").text().replace('回应', '')
                time_text = item(".main-meta").text()
                csv_writer.writerow([movie_title, name, title, href, content, up, comment, time_text])
    
    
    def download_one_page(url: str) -> None:
        html = get_page_source(url)
        parse_page_source(html)
        print(url, "提取完毕")
    
    
    if __name__ == "__main__":
        try:
            with ThreadPoolExecutor(max_workers=50) as t:
                for i in range(0, 80, 20):
                    t.submit(download_one_page, f"https://movie.douban.com/review/best/?start={i}")
        except Exception as e:
            print(f"影评数据爬取失败,错误信息:{str(e)}")
    

    10. 协程

    import asyncio
    import time
    
    
    # async def func():
    #     print("你好,我是薇尔莉特")
    #
    #
    # if __name__ == '__main__':
    #     g = func() # 此时的函数是异步协程函数,函数执行得到的是一个协程对象
    #     asyncio.run(g) # 协程程序运行需要asyncio模块的支持
    
    
    async def func1():
        print("我是甲")
        await asyncio.sleep(3)
        print("我是甲")
    
    
    async def func2():
        print("我是乙")
        await asyncio.sleep(2)
        print("我是乙")
    
    
    async def func3():
        print("我是丙")
        await asyncio.sleep(4)
        print("我是丙")
    
    
    # 定义主异步函数,所有异步逻辑都放在这里
    async def main():
        await asyncio.gather(func1(), func2(), func3())
    
    
    if __name__ == '__main__':
        t1 = time.time()
        # 一次性启动多个任务(协程)
        asyncio.run(main())
        t2 = time.time()
        print(t2 - t1)
    
    10.1. aiohttp 模块
    import asyncio
    import aiohttp
    
    urls = [
        "https://pixnio.com/free-images/2026/01/12/2026-01-12-04-50-14-576x384.jpg",
        "https://pixnio.com/free-images/2026/01/01/2026-01-01-11-01-36-576x384.jpeg",
        "https://pixnio.com/free-images/2025/08/18/2025-08-18-10-31-57-576x324.jpg"
    ]
    
    
    async def aiodownload(url: str):
        name = url.rsplit("/", 1)[1]  # 从右边切,切一次,得到[1]位置的内容
        try:
            headers = {
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0"
            }
            async with aiohttp.ClientSession() as session:
                async with session.get(url, headers=headers) as response:
                    response.raise_for_status()
                    with open(name, mode="wb") as f:
                        f.write(await response.content.read())
            print(f"{name} 下载完成")
        except Exception as e:
            print(f"{name} 下载失败:{str(e)}")
    
    
    async def main():
        tasks = []
        for url in urls:
            tasks.append(aiodownload(url))
        await asyncio.gather(*tasks)  # *解包
    
    
    if __name__ == '__main__':
        asyncio.run(main())
    
    10.2. 实操案例
    # https://dushu.baidu.com/api/pc/getCatalog?data={"book_id":"4306063500"}
    # https://dushu.baidu.com/api/pc/getChapterContent?data={"book_id":"4306063500","cid":"4306063500|1569782244","need_bookinfo":1}
    
    """
    1. 同步操作:访问getCatalog 拿到所有章节的cid和名称
    2. 异步操作:访问getChapterContent 下载所有的文章内容
    """
    import asyncio
    import json
    
    import aiofiles
    import aiohttp
    
    HEADERS = {
        "Referer": "https://dushu.baidu.com/",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0"
    }
    BOOK_ID = "4306063500"
    
    
    async def getChapterContent(session, cid, b_id, title):
        try:
            data = json.dumps({
                "book_id": b_id,
                "cid": f"{b_id}|{cid}",
                "need_bookinfo": 1
            })
            params = {"data": data}
    
            # 复用ClientSession,减少连接开销
            async with (session.get(
                url="https://dushu.baidu.com/api/pc/getChapterContent",
                params=params,
                headers=HEADERS,
                timeout=aiohttp.ClientTimeout(total=15))
                        as response):
                dic = await response.json()
                async with aiofiles.open(title, "w", encoding="utf-8") as f:
                    await f.write(dic["data"]["novel"]["content"])
            print(f"成功下载:{title}")
        except Exception as e:
            print(f"下载失败 {title}{str(e)}")
    
    
    async def getCatalog():
        url = f"https://dushu.baidu.com/api/pc/getCatalog?data={json.dumps({'book_id': BOOK_ID})}"
        async with aiohttp.ClientSession() as session:  # 创建全局session,复用连接
            try:
                async with session.get(url, headers=HEADERS, timeout=10) as response:
                    response.raise_for_status()
                    dic = await response.json()
                tasks = []
                items = dic["data"]["novel"]["items"]
                for item in items:
                    title = item["title"]
                    cid = item["cid"]
                    # 准备异步任务
                    tasks.append(getChapterContent(session, cid, BOOK_ID, title))
                await asyncio.gather(*tasks)
            except Exception as e:
                print(f"获取目录失败:{str(e)}")
    
    
    if __name__ == '__main__':
        asyncio.run(getCatalog())
        print("
    所有章节下载任务执行完毕!")
    

    11. m3u8 视频爬取合并

    # 
    # 一般的视频网站是怎么做的?
    # 用户上传 -> 转码(把视频做处理,2K,1080,标清) -> 切片处理(把单个的文件进行拆分) 60
    # 用户在进行拉进进度条的时候
    # ==============================================
    # 需要一个文件记录:1.视频播放顺序,2.视频存放的路径.
    # M3U8 txt json => 文本
    import asyncio
    import os
    import re
    
    import aiohttp
    import requests
    
    """
    想要抓取一个视频:
    1. 找到m3u8(各种手段)
    2. 通过m3u8下载到ts文件
    3. 可以通过各种手段(不仅是编程手段) 把ts文件合并为一个mp4文件
    """
    
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0"
    }
    
    # 创建video文件夹(避免下载时找不到路径)
    if not os.path.exists("video"):
        os.makedirs("video")
    
    
    def extract_m3u8_url_from_html(html):
        pattern = re.compile(r'https://vip1.lz-cdn5.com/.*?.m3u8', re.S)
        match = pattern.search(html)
    
        if match:
            return match.group(0).replace('/', '/')
        else:
            print("未找到m3u8的url字段")
            return None
    
    
    def extract_m3u8_url_from_file(m3u8_url01):
        with open("紫罗兰剧场版.m3u8", mode="r", encoding="utf-8") as f:
            suffix = ""
            lines = f.readlines()
            for line in lines:
                line = line.strip()
                if line and line.endswith('.m3u8'):
                    suffix = line
                    break
            if suffix:
                return m3u8_url01.rsplit("/", 1)[0] + '/' + suffix
            else:
                return None
    
    
    # 异步下载单个ts文件
    async def download_single_ts(session, ts_url, save_path):
        try:
            async with session.get(ts_url, headers=headers) as resp:
                if resp.status == 200:
                    with open(save_path, "wb") as f:
                        f.write(await resp.read())
                    print(f"{ts_url} 下载完成")
                else:
                    print(f"{ts_url} 下载失败,状态码:{resp.status}")
        except Exception as e:
            print(f"{ts_url} 下载异常:{e}")
    
    
    # 异步批量下载ts文件
    async def download_ts_async(m3u8_url02):
        # 读取m3u8文件,提取所有ts链接
        ts_tasks = []
        with open("紫罗兰剧场版.m3u8", mode="r", encoding="utf-8") as f:
            lines = f.readlines()
            for line in lines:
                line = line.strip()
                if line.startswith('#'):
                    continue
                # 拼接完整ts下载地址
                ts_url = m3u8_url02.rsplit("/", 1)[0] + '/' + line
                save_path = f"video/{line}"
                # 创建异步任务
                ts_tasks.append((ts_url, save_path))
    
        # 创建异步会话,并发下载
        async with aiohttp.ClientSession() as session:
            tasks = []
            # 遍历ts_tasks,逐个创建任务并添加到列表
            for url, path in ts_tasks:
                task = asyncio.create_task(download_single_ts(session, url, path))
                tasks.append(task)
            # 等待所有任务完成
            await asyncio.gather(*tasks)
    
    
    def merge_ts():
        lst = []
        # 读取m3u8文件,提取ts文件名
        with open("紫罗兰剧场版.m3u8", mode="r", encoding="utf-8") as f:
            for line in f:
                if line.startswith("#"):  # 跳过注释行
                    continue
                line = line.strip()  # 去除换行/空格
                # 坑,cmd路径要用反斜杠''
                lst.append(f'"video{line}"')  # 拼接ts文件路径
    
        # 把列表用"+"连接(Windows copy /b需要用+拼接文件)
        s = "+".join(lst)
        # 执行Windows合并命令(/b表示二进制模式)
        os.system(f'copy /b {s} "movie.mp4"')
        print("搞定!")
    
    
    def main():
        url = "https://ifana.cc/play/6073-1-1.html"
    
        # 从源码中提取m3u8_url
        resp01 = requests.get(url, headers=headers)
        resp01.encoding = "utf-8"
        m3u8_url01 = extract_m3u8_url_from_html(resp01.text)
        print(m3u8_url01)
        resp01.close()
        if not m3u8_url01:
            return
    
        # 提取真实m3u8_url后缀
        resp02 = requests.get(m3u8_url01, headers=headers)
        resp02.encoding = "utf-8"
        with open("紫罗兰剧场版.m3u8", "wb") as f:
            f.write(resp02.content)
        resp02.close()
        m3u8_url02 = extract_m3u8_url_from_file(m3u8_url01)
        print(m3u8_url02)
        if not m3u8_url02:
            return
    
        # 下载m3u8
        resp03 = requests.get(m3u8_url02, headers=headers)
        resp03.encoding = "utf-8"
        with open("紫罗兰剧场版.m3u8", "wb") as f:
            f.write(resp03.content)
        resp03.close()
    
        # 异步下载ts文件
        asyncio.run(download_ts_async(m3u8_url02))
    
        # 合并视频
        merge_ts()
    
    
    if __name__ == '__main__':
        main()
    

    12. Selenium

    12.1. 基本操作
    import time
    
    from selenium.webdriver import Edge, Keys, ActionChains
    from selenium.webdriver.common.by import By
    from selenium.webdriver.edge.options import Options
    
    # 创建Edge选项对象
    edge_options = Options()
    # 禁用自动关闭
    edge_options.add_experimental_option("detach", True)
    
    web = Edge(options=edge_options)
    web.get("https://movie.douban.com/")
    
    # 模拟遮挡广告去除
    web.execute_script("""
        const movieAnnualLink = document.querySelector('.movieannual');
        if (movieAnnualLink) {
            movieAnnualLink.remove();
        }
    """)
    
    # 找到输入框,输入电影名称,搜索
    web.find_element(By.XPATH, '//*[@id="inp-query"]').send_keys("紫罗兰永恒花园", Keys.ENTER)
    # 等待搜索结果
    time.sleep(1)
    
    # 数据提取
    items = web.find_elements(By.XPATH, '//div[contains(@class, "item-root")]')
    
    for item in items:
        title = item.find_element(By.XPATH, './div/div[1]/a')
        # 在新标签页中打开
    
        # 1.按住Ctrl键点击链接,在新标签页打开
        ActionChains(web).key_down(Keys.CONTROL).click(title).key_up(Keys.CONTROL).perform()
    
        # 2.通过JS设置链接的target属性为_blank
        # web.execute_script("arguments[0].setAttribute('target', '_blank');", title)
    
        # 此时,在浏览器这边. 我们看到的内容已经是详情页的内容了:
        # 但是,在selenium的眼中. 我们依然在首页.
        # 所以,必须得让selenium去调整它的视角
        # 切换到最后一个窗口
        web.switch_to.window(web.window_handles[-1])
        h2 = web.find_element(By.XPATH, '//div[@class="related-info"]/h2/i')
        print(h2.text)
        time.sleep(0.25)
        summary = web.find_element(By.XPATH, '//div[@id="link-report-intra"]/span')
        print(summary.text)
        time.sleep(0.25)
        print('
    ')
        web.close()
        web.switch_to.window(web.window_handles[0])
        time.sleep(0.25)
    
    web.quit()  # 关闭浏览器
    
    12.2. 切换 iframe
    from selenium.webdriver import Edge
    from selenium.webdriver.common.by import By
    from selenium.webdriver.edge.options import Options
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.support.wait import WebDriverWait
    
    edge_options = Options()
    # 禁用自动关闭
    edge_options.add_experimental_option("detach", True)
    
    web = Edge(options=edge_options)
    web.get("https://www.126.com/")
    
    # 切换到iframe
    iframe = WebDriverWait(web, 10).until(
        EC.presence_of_element_located((By.XPATH, '//iframe[starts-with(@id, "x-URS-iframe")]'))
    )
    web.switch_to.frame(iframe)
    
    # 等待iframe可用并直接切换(无需先定位再切换)
    # WebDriverWait(web, 10).until(
    #     EC.frame_to_be_available_and_switch_to_it((By.XPATH, '//iframe[starts-with(@id, "x-URS-iframe")]'))
    # )
    
    account = web.find_element(By.NAME, 'email')
    ac_placeholder = account.get_property('placeholder')
    print(ac_placeholder)
    pwd = web.find_element(By.NAME, 'password')
    pwd_placeholder = pwd.get_property('placeholder')
    print(pwd_placeholder)
    
    # 跳出iframe
    web.switch_to.parent_frame()
    title = web.find_element(By.XPATH, '//*[@class="headerTitle"]')
    print(title.text)
    
    12.3. 切换下拉列表
    from selenium.webdriver import Edge
    from selenium.webdriver.common.by import By
    from selenium.webdriver.edge.options import Options
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.support.select import Select
    from selenium.webdriver.support.wait import WebDriverWait
    
    # 配置无头信息
    edge_options = Options()
    edge_options.add_argument("--headless")
    edge_options.add_argument("--disable-gpu")
    web = Edge(options=edge_options)
    
    web.get("https://www.endata.com.cn/BoxOffice/B0/Year/index.html")
    
    sel = web.find_element(By.XPATH, '//*[@id="OptionDate"]')
    sel_new = Select(sel)
    
    print(len(sel_new.options))  # 所有的选项 0 1 2 3 4 5 6
    
    for i in range(len(sel_new.options)):
        sel_new.select_by_index(i)  # 根据位置切换
        WebDriverWait(web, 10).until(
            EC.presence_of_element_located((By.XPATH, '//*[@id="TableList"]/table/tbody/tr'))
        )
        trs = web.find_elements(By.XPATH, '//*[@id="TableList"]/table/tbody/tr')
        for tr in trs:
            print(tr.text)
    

    13. Scrapy

    13.1. 工作原理

    常规爬虫逻辑:

    scrapy 框架工作逻辑:

    整个工作流程:

    13.2. 基本使用

    控制台执行scrapy startproject 项目名称

    这里的示例项目名称使用 tianya,并设置为 Resource Root

    进入到 tianya目录,控制台执行 scrapy genspider ty "tianya.org"

    流程总结:

    要使用到 redis,所以需安装依赖:redis、scrapy-redis

    settings.py⬇️

    BOT_NAME = "tianya"
    
    SPIDER_MODULES = ["tianya.spiders"]
    NEWSPIDER_MODULE = "tianya.spiders"
    LOG_LEVEL = "WARNING"
    ADDONS = {}
    
    ROBOTSTXT_OBEY = False
    
    CONCURRENT_REQUESTS_PER_DOMAIN = 1
    DOWNLOAD_DELAY = 1
    
    ITEM_PIPELINES = {
       "tianya.pipelines.TianyaPipeline": 300,
    }
    
    FEED_EXPORT_ENCODING = "utf-8"
    

    items.py⬇️

    import scrapy
    
    
    class TianyaItem(scrapy.Item):
        title = scrapy.Field()  # 标题
        author = scrapy.Field()  # 作者
        reply = scrapy.Field()  # 回复数
        like = scrapy.Field()  # 点赞数
        mark = scrapy.Field()  # 收藏数
    

    ty.py⬇️

    import scrapy
    from redis import Redis
    
    from tianya.items import TianyaItem
    
    
    # 有可能产生重复的数据
    # 1. 使用python的set集合去重
    # 2. 使用redis的set集合去重(推荐)
    # 用redis有两种方案去重:
    # 1. url,优点:简单,缺点:如果url内部进行了更新,可能会忽略掉一些数据
    # 2. 数据,优点:准确性高,缺点:若数据集庞大,对redis来说会产生BigKey
    
    class TySpider(scrapy.Spider):
        name = "ty"
        allowed_domains = ["tianya.org"]
        start_urls = ["https://www.tianya.org/"]
    
        def __init__(self, name=None, **kwargs):
            self.red = Redis(
                host='127.0.0.1',
                port=6379,
                db=0,
                decode_responses=False,
                encoding="utf-8",
            )
            # 让父类能初始化
            super(TySpider, self).__init__(name, **kwargs)
    
        def parse(self, resp, **kwargs):
            # 进入详情页
            li_list = resp.xpath("//ul[@class='list-unstyled threadlist mb-0']/li")
            for li in li_list:
                href = li.xpath("./@data-href").extract_first()
                detail_url = resp.urljoin(href)
                result = self.red.sismember("tianya:ty:detail:url", detail_url)
                if result:
                    print(f"该url已经被抓取过{detail_url}")
                else:
                    yield scrapy.Request(
                        url=detail_url,
                        callback=self.parse_detail,
                        **kwargs
                    )
    
        def parse_detail(self, resp):
            t = TianyaItem()
            title = resp.xpath("//div[@class='card card-thread']/div/div/div/h4/text()").extract_first()
            author = resp.xpath("//span[@class='username']/a/text()").extract_first()
            func_num_list = resp.xpath("//div[contains(@class, 'thread_left_func_num')]/text()").extract()
            t['title'] = title.strip() if title else None
            t['author'] = author.strip() if author else None
            t['reply'] = func_num_list[0].strip() if len(func_num_list) >= 1 else None
            t['like'] = func_num_list[1].strip() if len(func_num_list) >= 2 else None
            t['mark'] = func_num_list[2].strip() if len(func_num_list) >= 3 else None
            self.red.sadd("tianya:ty:detail:url", resp.url)
            yield t
    

    pipelines.py⬇️

    class TianyaPipeline:
        def process_item(self, item):
            # 判断,是否在redis中存储了,若已存储就不进入数据库
            print(item)
            return item
    

    **执行 scrapy crawl ty**⬇️

    (.venv) PS G:PyCharm-2024-workplacePythonLearn第六章_Scrapy框架01_基础入门tianya> scrapy crawl ty
    {'author': '木子居士',
     'like': '0',
     'mark': '0',
     'reply': '3',
     'title': '兄弟们,今年计划亏多少'}
    {'author': '马克思',
     'like': '0',
     'mark': '0',
     'reply': '3',
     'title': '天涯社区网速测试如何?'}
    {'author': None,
     'like': '0',
     'mark': '0',
     'reply': '0',
     'title': '出售维修二手租赁回收安捷伦 T1141A RFID HF测试仪'}
    {'author': '马克思', 'like': '0', 'mark': '0', 'reply': '2', 'title': '新人求助'}
    {'author': 'Snow',
     'like': '23',
     'mark': '14',
     'reply': '378',
     'title': '用我30年的经历,为你揭开周易的神秘-四书五经丶(6)'}
    {'author': '点逐清风',
     'like': '111',
     'mark': '40',
     'reply': '1387',
     'title': '(长篇)女性秘史◆那些风华绝代、风情万种的女人,为你打开女人的所有秘密'}
    {'author': '小笨笨',
     'like': '28',
     'mark': '15',
     'reply': '447',
     'title': '一个潜水多年的体制内的生意人来实际谈谈老百姓该怎么办?'}
    {'author': '龙井茶',
     'like': '26',
     'mark': '17',
     'reply': '475',
     'title': '奶奶遗留一本怪书,里面都是一些吓人古术,给我带来了可怕的经历'}
    {'author': '兰风筝',
     'like': '7',
     'mark': '0',
     'reply': '283',
     'title': '有这样的女友,你是什么感受'}
    {'author': '马克思',
     'like': '7',
     'mark': '0',
     'reply': '198',
     'title': '这样的能结婚吗??'}
    {'author': 'ighaonr',
     'like': '1',
     'mark': '0',
     'reply': '99',
     'title': '迷糊不迷糊你看了在说'}
    {'author': '鑫伍',
     'like': '16',
     'mark': '7',
     'reply': '238',
     'title': '【经济专栏】赚未来十年的钱【已出版】'}
    {'author': 'luyi',
     'like': '0',
     'mark': '0',
     'reply': '37',
     'title': '想她了可经打给她,建行卡号没变哦!!!'}
    {'author': '马克思',
     'like': '13',
     'mark': '12',
     'reply': '365',
     'title': '【国庆礼包】天涯神帖1-211部大放送(2025/10/4修复)'}
    {'author': '啦啦啦',
     'like': '230',
     'mark': '111',
     'reply': '2822',
     'title': '(全网最全最详细)天涯神贴合集1000篇 | 超全合集,无需解压'}
    {'author': 'chenpingan',
     'like': '2',
     'mark': '0',
     'reply': '187',
     'title': '下班了,来波福利,'}
    {'author': 'oylhoylh',
     'like': '91',
     'mark': '28',
     'reply': '896',
     'title': '【寒门再难出贵子】神帖限时开放'}
    {'author': 'yugaochao',
     'like': '0',
     'mark': '0',
     'reply': '59',
     'title': '异域风情!!不一样的美!!'}
    {'author': '247574',
     'like': '4',
     'mark': '0',
     'reply': '235',
     'title': '短裙过膝袜,绝对YYDS'}
    {'author': None, 'like': '0', 'mark': '0', 'reply': '1', 'title': '为什么需要礼拜五'}
    

    redis 数据库⬇️

    13.3. 分布式

    目录结构⬇️

    items.py 和 pipelines.py 保持不变

    ty.py 改动如下⬇️

    import scrapy
    from scrapy_redis.spiders import RedisSpider
    
    from tianya2.items import TianyaItem
    
    
    class TySpider(RedisSpider):
        name = "ty"
        allowed_domains = ["tianya.org"]
        # start_urls = ["https://www.tianya.org/"]
        redis_key = "ty_start_url"
    
        def parse(self, resp, **kwargs):
            # 自定义请求头
            custom_headers = {
                'Cookie': 'bbs_token=dnsSNob06Ok7KtBitQaxQjh5DGbAOfa4lAIqzSqHVljjwm9v; Hm_lvt_bdc65c3d1a40d80d03c75152017b11eb=1768646265; bbs_sid=7u2q69307h7c0na0lv64rur2cc'
            }
            # 进入详情页
            li_list = resp.xpath("//ul[@class='list-unstyled threadlist mb-0']/li")
            for li in li_list:
                href = li.xpath("./@data-href").extract_first()
                # 交给 Scrapy-Redis 做去重和调度
                yield scrapy.Request(
                    url=resp.urljoin(href),
                    callback=self.parse_detail,
                    headers=custom_headers,
                    **kwargs
                )
    
        def parse_detail(self, resp):
            t = TianyaItem()
            title = resp.xpath("//div[@class='card card-thread']/div/div/div/h4/text()").extract_first()
            author = resp.xpath("//span[@class='username']/a/text()").extract_first()
            func_num_list = resp.xpath("//div[contains(@class, 'thread_left_func_num')]/text()").extract()
            t['title'] = title.strip() if title else None
            t['author'] = author.strip() if author else None
            t['reply'] = func_num_list[0].strip() if len(func_num_list) >= 1 else None
            t['like'] = func_num_list[1].strip() if len(func_num_list) >= 2 else None
            t['mark'] = func_num_list[2].strip() if len(func_num_list) >= 3 else None
            yield t
    

    使用 redis 的布隆过滤器去重,所以需安装依赖:scrapy-redis-bloomfilter

    settings.py⬇️

    BOT_NAME = "tianya2"
    
    SPIDER_MODULES = ["tianya2.spiders"]
    NEWSPIDER_MODULE = "tianya2.spiders"
    # debug < info < warning < error < critical
    LOG_LEVEL = "INFO"
    ADDONS = {}
    
    ROBOTSTXT_OBEY = False
    CONCURRENT_REQUESTS_PER_DOMAIN = 1
    DOWNLOAD_DELAY = 1
    
    # 配置全局请求头
    DEFAULT_REQUEST_HEADERS = {
        'UserAgent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0'
    }
    
    # ========== redis 相关配置 ==========
    REDIS_PARAMS = {
        'host': '127.0.0.1',
        'port': 6379,
        'db': 0,
    }
    
    # ========== scrapy_redis 相关配置 ==========
    # 分布式调度器
    SCHEDULER = "scrapy_redis.scheduler.Scheduler"
    # 分布式去重 (这里使用布隆过滤器)
    DUPEFILTER_CLASS = "scrapy_redis_bloomfilter.dupefilter.RFPDupeFilter"
    # 哈希函数个数,默认为 6
    BLOOMFILTER_HASH_NUMBER = 6
    # BloomFilter 的 bit 参数,默认为 30,占用 128MB 空间,去重量级为 1 亿
    BLOOMFILTER_BIT = 30
    # 断点续爬 (可选)
    SCHEDULER_PERSIST = True
    
    ITEM_PIPELINES = {
        "tianya2.pipelines.TianyaPipeline": 300,
        "scrapy_redis.pipelines.RedisPipeline": 301,
    }
    
    FEED_EXPORT_ENCODING = "utf-8"
    

    在控制台 tianya2 文件夹目录下执行命令 scrapy crawl ty

    进入 redis-cli 执行 lpush ty_start_url https://www.tianya.org/命令

    控制台输出如下⬇️

    redis 数据库⬇️

    使用 MySQL 存储数据⬇️

    创建 spider_test 数据库:

    创建 new 数据表:

    -- 天涯论坛爬虫数据存储表:存储抓取的帖子基础信息
    CREATE TABLE `news` (
      `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID,自增唯一标识',
      `title` varchar(255) NOT NULL COMMENT '帖子标题',
      `author` varchar(255) NOT NULL COMMENT '帖子发布作者',
      `reply` int(11) NOT NULL COMMENT '帖子回复数',
      `like` int(11) NOT NULL COMMENT '帖子点赞数(`like`为MySQL关键字,需反引号包裹)',
      `mark` int(11) NOT NULL COMMENT '帖子收藏数',
      `url` varchar(255) NOT NULL COMMENT '帖子唯一链接(作为唯一键,避免重复抓取)',
      PRIMARY KEY (`id`) COMMENT '主键约束:基于自增ID',
      UNIQUE KEY `uk_url` (`url`) COMMENT '唯一键约束:保证帖子URL不重复,避免重复插入数据'
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='天涯论坛帖子爬虫数据表';
    

    安装依赖:pymysql

    settings.py 添加配置:

    ITEM_PIPELINES = {
        "tianya2.pipelines.TianyaPipeline": 300,
        # "scrapy_redis.pipelines.RedisPipeline": 301,
        "tianya2.pipelines.MysqlPipeline": 302,
    }
    
    MYSQL_CONFIG = {
        'host': '127.0.0.1',
        'port': 3306,
        'user': 'root',
        'password': '你的MySQL密码',
        'db': 'spider_test',
        'charset': 'utf8mb4'
    }
    

    pipelines.py 代码:

    import pymysql
    from twisted.enterprise import adbapi
    
    
    class TianyaPipeline:
        def process_item(self, item, spider):
            spider.logger.info(f"成功抓取到了 {item}")
            return item
    
    
    class MysqlPipeline:
        def __init__(self, db_pool):
            self.db_pool = db_pool
    
        @classmethod
        def from_crawler(cls, crawler):
            db_params = crawler.settings.get('MYSQL_CONFIG')
            db_pool = adbapi.ConnectionPool(
                'pymysql',
                **db_params,
                autocommit=True,
                cursorclass=pymysql.cursors.DictCursor
            )
            return cls(db_pool)
    
        def process_item(self, item, spider):
            # 异步插入数据
            query = self.db_pool.runInteraction(self.insert_item, item)
            query.addErrback(self.handle_error, item, spider)
            return item
    
        def insert_item(self, cursor, item):
            insert_sql = """
            INSERT INTO news(title, author, reply, `like`, mark, url) 
            VALUES (%s, %s, %s, %s, %s, %s)
            """
            cursor.execute(insert_sql, (
                item.get('title') or ' ',
                item.get('author') or ' ',
                item.get('reply', 0),
                item.get('like', 0),
                item.get('mark', 0),
                item.get('url') or ' ',
            ))
    
        def handle_error(self, failure, item, spider):
            spider.logger.error(f"MySQL插入失败:{failure},Item:{item}")
    
        def close_spider(self, spider):
            self.db_pool.close()
    

    按照之前的步骤启动爬虫程序,可观察到数据已成功入库:

    本文地址:https://www.yitenyun.com/2915.html

    搜索文章

    Tags

    #服务器 #python #pip #conda #人工智能 #微信 #ios面试 #ios弱网 #断点续传 #ios开发 #objective-c #ios #ios缓存 #远程工作 #Trae #IDE #AI 原生集成开发环境 #Trae AI 香港站群服务器 多IP服务器 香港站群 站群服务器 #kubernetes #笔记 #平面 #容器 #linux #学习方法 #运维 #log4j #ollama #飞牛nas #fnos #kylin #docker #arm #hadoop #hbase #hive #zookeeper #spark #kafka #flink #科技 #深度学习 #自然语言处理 #神经网络 #银河麒麟高级服务器操作系统安装 #银河麒麟高级服务器V11配置 #设置基础软件仓库时出错 #银河麒高级服务器系统的实操教程 #生产级部署银河麒麟服务系统教程 #Linux系统的快速上手教程 #低代码 #爬虫 #音视频 #飞书 #语言模型 #大模型 #ai #ai大模型 #agent #学习 #AI编程 #ARM服务器 # GLM-4.6V # 多模态推理 #大数据 #职场和发展 #程序员创富 #PyTorch #模型训练 #星图GPU #华为云 #部署上线 #动静分离 #Nginx #新人首发 #MobaXterm #ubuntu #ide #java #开发语言 #前端 #javascript #架构 #ssh #经验分享 #安卓 #分阶段策略 #模型协议 #fastapi #html #css #harmonyos #鸿蒙PC #langchain #数据库 #nginx #开源 #C++ #Reactor #windows #物联网 #websocket #自动化 #ansible #云计算 #进程控制 #驱动开发 #c++ #github #git #tcp/ip #网络 #qt #私有化部署 #unity #c# #游戏引擎 #aws #区块链 #测试用例 #生活 #word #umeditor粘贴word #ueditor粘贴word #ueditor复制word #ueditor上传word图片 #android #腾讯云 #Conda # 私有索引 # 包管理 #gemini #gemini国内访问 #gemini api #gemini中转搭建 #Cloudflare #pytorch #cpolar #fabric #postgresql #openHiTLS #TLCP #DTLCP #密码学 #商用密码算法 #vue上传解决方案 #vue断点续传 #vue分片上传下载 #vue分块上传下载 #jar #数信院生信服务器 #Rstudio #生信入门 #生信云服务器 #node.js #大模型学习 #AI大模型 #大模型教程 #大模型入门 #风控模型 #决策盲区 #算法 #牛客周赛 #dify #ci/cd #jenkins #gitlab #内网穿透 #mysql #RTP over RTSP #RTP over TCP #RTSP服务器 #RTP #TCP发送RTP #云原生 #iventoy #VmWare #OpenEuler #sql #AIGC #agi #矩阵 #线性代数 #AI运算 #向量 #机器学习 #Harbor #flutter #vscode #文心一言 #AI智能体 #pycharm #Ansible # 自动化部署 # VibeThinker #centos #svn #后端 #mobaxterm #计算机视觉 #http #项目 #高并发 #缓存 #硬件工程 #边缘计算 #mcp #mcp server #AI实战 #spring cloud #spring #vue.js #json #重构 #阿里云 #serverless #diskinfo # TensorFlow # 磁盘健康 #microsoft #儿童书籍 #儿童诗歌 #童话故事 #经典好书 #儿童文学 #好书推荐 #经典文学作品 #鸿蒙 #c语言 #FTP服务器 #设备驱动 #芯片资料 #网卡 #ecmascript #elementui #开源软件 #数学建模 #2026年美赛C题代码 #2026年美赛 #php #FaceFusion # Token调度 # 显存优化 #spring boot #java大文件上传 #java大文件秒传 #java大文件上传下载 #java文件传输解决方案 #超算服务器 #算力 #高性能计算 #仿真分析工作站 #springboot #java-ee #prometheus #分布式 #华为 #iBMC #UltraISO #shell #CPU利用率 #性能优化 #mongodb #数据结构 #jmeter #功能测试 #软件测试 #自动化测试 #进程 #web安全 #安全 #mcu #蓝桥杯 #企业开发 #ERP #项目实践 #.NET开发 #C#编程 #编程与数学 #正则 #正则表达式 #信息与通信 #内存治理 #django #多个客户端访问 #IO多路复用 #回显服务器 #TCP相关API #mvp #个人开发 #设计模式 #llama #opencv #Ubuntu服务器 #硬盘扩容 #命令行操作 #VMware #stm32 #Windows 更新 #流程图 #论文阅读 #信息可视化 #PyCharm # 远程调试 # YOLOFuse #搜索引擎 #导航网 #select #大语言模型 #长文本处理 #GLM-4 #Triton推理 #嵌入式 #Dell #PowerEdge620 #内存 #硬盘 #RAID5 #MCP #MCP服务器 #游戏 #时序数据库 #程序人生 #科研 #博士 #产品经理 #ui #团队开发 #墨刀 #figma #web #webdav #chatgpt #DeepSeek #AI #DS随心转 #系统架构 #网络协议 #FL Studio #FLStudio #FL Studio2025 #FL Studio2026 #FL Studio25 #FL Studio26 #水果软件 #vim #gcc #yum #uni-app #小程序 #notepad++ #es安装 #redis #lvs #负载均衡 #鸭科夫 #逃离鸭科夫 #鸭科夫联机 #鸭科夫异地联机 #开服 #flask #毕业设计 #rocketmq #Linux #TCP #线程 #线程池 #RAGFlow #DeepSeek-R1 #powerpoint #Com #CFD #课程设计 #jetty #jvm #SSH # ProxyJump # 跳板机 #哈希算法 #散列表 #dreamweaver #HCIA-Datacom #H12-811 #题库 #最新题库 #计算机网络 #线性回归 #transformer #scrapy #服务器繁忙 #leetcode #企业微信 #wsl #L2C #勒让德到切比雪夫 #Android #Bluedroid #钉钉 #机器人 #LLM #3d #arm开发 #嵌入式硬件 #AI写作 #Agent #程序员 #ffmpeg #ssl #深度优先 #DFS #学习笔记 #jdk #udp #酒店客房管理系统 #毕设 #论文 #https #SSM 框架 #孕期健康 #产品服务推荐 #推荐系统 #用户交互 #数据集 #零售 #todesk #AI产品经理 #大模型开发 #mmap #nio #rabbitmq #protobuf #我的世界 #游戏私服 #云服务器 #PowerBI #企业 #golang #vllm #Streamlit #Qwen #本地部署 #AI聊天机器人 #堡垒机 #安恒明御堡垒机 #windterm #自动驾驶 #京东云 #语音识别 #能源 #servlet #阻塞队列 #生产者消费者模型 #服务器崩坏原因 #数据仓库 #智能手机 #vue3 #天地图 #403 Forbidden #天地图403错误 #服务器403问题 #天地图API #部署报错 #autosar #AI论文写作工具 #学术论文创作 #论文效率提升 #MBA论文写作 #everything #AB包 #操作系统 #cnn #Tracker 服务器 #响应最快 #torrent 下载 #2026年 #Aria2 可用 #迅雷可用 #BT工具通用 #gitee #单片机 #svm #amdgpu #kfd #ROCm #网络安全 #数模美赛 #matlab #whisper #就业 #openclaw #面试 #YOLO #分类 #claude #abtest #全能视频处理软件 #视频裁剪工具 #视频合并工具 #视频压缩工具 #视频字幕提取 #视频处理工具 #逻辑回归 #电脑 #DisM++ # 系统维护 #Canal #信号处理 #目标跟踪 #蓝耘智算 #社科数据 #数据分析 #数据挖掘 #数据统计 #经管数据 #守护进程 #复用 #screen #sqlserver #paddlepaddle #其他 #压枪 #支持向量机 #启发式算法 #树莓派4b安装系统 #oracle #CISSP #CISSP考点 #信息安全 #CISSP哪里考 #公众号:厦门微思网络 #+微信号:xmweisi #排序算法 #插入排序 #Chat平台 #ARM架构 #考研 #软件工程 #pjsip #openresty #lua #电气工程 #C# #PLC #GB/T4857 #GB/T4857.17 #GB/T4857测试 #claude code #codex #code cli #ccusage #Ascend #MindIE #OBC #SSH Agent Forwarding # PyTorch # 容器化 #twitter #求职招聘 #需求分析 #scala #测试工具 #压力测试 #ProCAST2025 #ProCast #脱模 #顶出 #应力计算 #铸造仿真 #变形计算 #ssm #laravel #里氏替换原则 #debian #幼儿园 #园长 #幼教 #推荐算法 #adb #若依 #quartz #框架 #1024程序员节 #sizeof和strlen区别 #sizeof #strlen #计算数据类型字节数 #计算字符串长度 #googlecloud #七年级上册数学 #有理数 #有理数的加法法则 #绝对值 #流量运营 #用户运营 #iphone #ModelEngine #银河麒麟操作系统 #openssh #华为交换机 #信创终端 #聚类 #银河麒麟 #系统升级 #信创 #国产化 #架构师 #软考 #系统架构师 #gpu算力 #金融 #金融投资Agent #AI大模型应用开发 #elasticsearch #版本控制 #Git入门 #开发工具 #代码托管 #ESXi #n8n #贪心算法 #pdf #ISP Pipeline #行缓冲 #智慧校园解决方案 #智慧校园一体化平台 #智慧校园选型 #智慧校园采购 #智慧校园软件 #智慧校园专项资金 #智慧校园定制开发 #LangGraph #模型上下文协议 #MultiServerMCPC #load_mcp_tools #load_mcp_prompt #dubbo #unity3d #服务器框架 #Fantasy #测试流程 #金融项目实战 #P2P #webrtc #llm #新浪微博 #前端框架 #智能路由器 #单元测试 #pytest #微信小程序 #visual studio code #prompt #react.js #串口服务器 #工业级串口服务器 #串口转以太网 #串口设备联网通讯模块 #串口服务器选型 #论文笔记 #游戏美术 #技术美术 #游戏策划 #游戏程序 #用户体验 #mamba #凤希AI伴侣 #生信 #Coze工作流 #AI Agent指挥官 #多智能体系统 #HBA卡 #RAID卡 #我的世界服务器搭建 #minecraft #VS Code调试配置 #journalctl #测试覆盖率 #可用性测试 #RAG #全链路优化 #实战教程 #wordpress #雨云 #LobeChat #vLLM #GPU加速 #lstm #智慧城市 #selenium #海外短剧 #海外短剧app开发 #海外短剧系统开发 #短剧APP #短剧APP开发 #短剧系统开发 #海外短剧项目 #macos #Cpolar #国庆假期 #服务器告警 #Node.js #漏洞检测 #CVE-2025-27210 #eBPF #SSH反向隧道 # Miniconda # Jupyter远程访问 #grafana #FRP #.net #homelab #Lattepanda #Jellyfin #Plex #Emby #Kodi #远程连接 #TensorRT # Triton # 推理优化 #asp.net大文件上传 #asp.net大文件上传下载 #asp.net大文件上传源码 #ASP.NET断点续传 #asp.net上传文件夹 #gpu #nvcc #cuda #nvidia #xeon #建筑缺陷 #红外 #结构体 #ping通服务器 #读不了内网数据库 #bug菌问答团队 #漏洞 #链表 #数码相机 # 公钥认证 #UDP套接字编程 #UDP协议 #网络测试 #HeyGem # 服务器IP访问 # 端口映射 #SSE #epoll #高级IO #Keycloak #Quarkus #AI编程需求分析 #无人机 #Deepoc #具身模型 #开发板 #未来 #asp.net #三种参数 #参数的校验 #fastAPI #tdengine #制造 #涛思数据 #机器视觉 #6D位姿 #计算机 #连锁药店 #连锁店 #Proxmox VE #虚拟化 #改行学it #硬件 #LoRA # RTX 3090 # lora-scripts #目标检测 #YOLO26 #YOLO11 #GPU服务器 #8U #硬件架构 #fiddler #rtmp #银河麒麟部署 #银河麒麟部署文档 #银河麒麟linux #银河麒麟linux部署教程 #ddos #windbg分析蓝屏教程 #ROS # 局域网访问 # 批量处理 #Modbus #IFix #文生视频 #CogVideoX #AI部署 #H5 #跨域 #发布上线后跨域报错 #请求接口跨域问题解决 #跨域请求代理配置 #request浏览器跨域 #react native #fpga开发 #LVDS #高速ADC #DDR #游戏机 #JumpServer #UDP的API使用 #环境搭建 #pandas #matplotlib #anaconda #虚拟环境 #双指针 #振镜 #振镜焊接 #tomcat #firefox #Modbus-TCP #rust #TURN # WebRTC # HiChatBox #流量监控 #ai编程 #azure #编辑器 #OCR #文字检测 #MC #SRS #流媒体 #直播 #数组 #fastmcp #ida #长文本理解 #glm-4 #推理部署 #glibc #几何学 #拓扑学 #链表的销毁 #链表的排序 #链表倒置 #判断链表是否有环 #中间件 #研发管理 #禅道 #禅道云端部署 #ONLYOFFICE #MCP 服务器 #电商 #zabbix #人脸识别 #人脸核身 #活体检测 #身份认证与人脸对比 #微信公众号 #STUN # TURN # NAT穿透 #蓝牙 #LE Audio #BAP #web3 #RAID #RAID技术 #磁盘 #存储 #GLM-4.6V-Flash-WEB # AI视觉 # 本地部署 #土地承包延包 #领码SPARK #aPaaS+iPaaS #数字化转型 #智能审核 #档案数字化 #进程创建与终止 #xlwings #Excel #maven #spine #typescript #npm #VPS #搭建 #bootstrap #chrome #embedding # 远程访问 # 服务器IP配置 #IndexTTS2 # 阿里云安骑士 # 木马查杀 #捷配 #pcb工艺 #MS #Materials #Karalon #AI Test #RustDesk #IndexTTS 2.0 #本地化部署 #Moltbot #YOLOv8 # 目标检测 # Docker镜像 #2026AI元年 #年度趋势 #文件IO #输入输出流 #国产PLM #瑞华丽PLM #瑞华丽 #PLM #tcpdump #markdown #建站 #跳槽 #业界资讯 #google #search #车辆排放 #SA-PEKS # 关键词猜测攻击 # 盲签名 # 限速机制 #多线程 #性能调优策略 #双锁实现细节 #动态分配节点内存 #Spring AI #STDIO协议 #Streamable-HTTP #McpTool注解 #服务器能力 #CMake #Make #C/C++ #Python #paddleocr #工具集 # IndexTTS 2.0 # 远程运维 #排序 # 高并发部署 #策略模式 #pencil #pencil.dev #设计 #K8s #镜像 #集群自动化 #vps #Anything-LLM #IDC服务器 #TFTP #客户端 #simulink #aiohttp #asyncio #异步 #性能测试 #LoadRunner #软件 #本地生活 #电商系统 #商城 #bytebase #sqlite #Playbook #AI服务器 #tensorflow #intellij-idea #database #idea #wps #学术写作辅助 #论文创作效率提升 #AI写论文实测 #工厂模式 #Triton # CUDA #p2p #SSH保活 #Miniconda #远程开发 #rdp #log #apache #海外服务器安装宝塔面板 #翻译 #开源工具 #Moltbook #Clawdbot #910B #SEO优化 #浏览器自动化 #python #openlayers #bmap #tile #server #vue #PyTorch 特性 #动态计算图 #张量(Tensor) #自动求导Autograd #GPU 加速 #生态系统与社区支持 #与其他框架的对比 #cascadeur #设计师 #vuejs #SSH免密登录 # GLM-4.6V-Flash-WEB # 显卡驱动备份 #联机教程 #局域网联机 #局域网联机教程 #局域网游戏 #虚拟机 #EMC存储 #存储维护 #NetApp存储 #简单数论 #埃氏筛法 #openEuler #Hadoop #DIY机器人工房 #nacos #银河麒麟aarch64 #uvicorn #uvloop #asgi #event #labview #集成测试 #yolov12 #研究生life #静脉曲张 #腿部健康 #spring native #智能一卡通 #门禁一卡通 #梯控一卡通 #电梯一卡通 #消费一卡通 #一卡通 #考勤一卡通 #远程访问 #远程办公 #飞网 #安全高效 #配置简单 #RK3576 #瑞芯微 #硬件设计 #SSH别名 #信令服务器 #Janus #MediaSoup #逆向工程 #ngrok #Java #Spring #Spring Boot #群晖 #音乐 #RPA #影刀RPA #AI办公 #社交智慧 #职场生存 #系统思维 #身体管理 #商务宴请 #拒绝油腻 #清醒日常 #微服务 #Jetty # CosyVoice3 # 嵌入式服务器 #iot #智能家居 #galeweather.cn #高精度天气预报数据 #光伏功率预测 #风电功率预测 #高精度气象 #SMTP # 内容安全 # Qwen3Guard #mybatis #X11转发 #可撤销IBE #服务器辅助 #私钥更新 #安全性证明 #双线性Diffie-Hellman #智能体 #贴图 #材质 #空间计算 #原型模式 #爱心代码 #表白代码 #爱心 #tkinter #情人节表白代码 #5G #平板 #交通物流 #智能硬件 #JT/T808 #车联网 #车载终端 #模拟器 #仿真器 #开发测试 #mapreduce # AI翻译机 # 实时翻译 #测评 #clickhouse #创业创新 #代理 #北京百思可瑞教育 #百思可瑞教育 #北京百思教育 #nas #音乐分类 #音频分析 #ViT模型 #Gradio应用 #鼠大侠网络验证系统源码 #监控 #自动化运维 #IO #AI赋能盾构隧道巡检 #开启基建安全新篇章 #以注意力为核心 #YOLOv12 #AI隧道盾构场景 #盾构管壁缺陷病害异常检测预警 #隧道病害缺陷检测 #插件 #r-tree #心理健康服务平台 #心理健康系统 #心理服务平台 #心理健康小程序 #risc-v #ms-swift # 一锤定音 # 大模型微调 #deepseek #bash #状态模式 #VibeVoice # 语音合成 #dba #SSH公钥认证 # 安全加固 #LabVIEW知识 #LabVIEW程序 #LabVIEW功能 #鸿蒙系统 #系统安全 #车载系统 #安全架构 #dynadot #域名 #Fun-ASR # 语音识别 # WebUI #密码 #cpp #Deepseek #gpt-3 #交互 #CUDA #Docker #excel #Fluentd #Sonic #日志采集 #NPU #CANN #企业架构治理 #电力企业IT架构 #IT架构设计 #迁移重构 #数据安全 #代码迁移 #Qwen3-14B # 大模型部署 # 私有化AI #restful #ajax #转行 #Claude #视频去字幕 #flume #外卖配送 #处理器模块 #现货库存 #价格优惠 #PM864AK01 #3BSE018161R1 #控制器模块 #大剑师 #nodejs面试题 #vp9 #Ubuntu #Steam #饥荒联机版 #零代码平台 #AI开发 #AutoDL #screen 命令 #命令模式 #运维开发 #opc ua #opc #模版 #函数 #类 #笔试 # GLM-TTS # 数据安全 #visual studio #图像处理 #yolo #支付 #指针 #敏捷流程 #esp32教程 #行为模式分析 #数据 #应用层 #跨领域 #敏感信息 #远程桌面 #远程控制 #高品质会员管理系统 #收银系统 #同城配送 #最好用的电商系统 #最好用的系统 #推荐的前十系统 #JAVA PHP 小程序 #Gunicorn #WSGI #Flask #并发模型 #容器化 #性能调优 #ipv6 #WEB #源代码管理 #chat #ceph #SAP #ebs #metaerp #oracle ebs #AI助手 #企业微信集成 #轻量大模型 #list #echarts #Rust ##程序员和算法的浪漫 #ue4 #ue5 #DedicatedServer #独立服务器 #专用服务器 #框架搭建 #SSH跳转 #NAS #飞牛NAS #NVR #EasyNVR #项目申报系统 #项目申报管理 #项目申报 #企业项目申报 #wpf #JAVA # IndexTTS # GPU集群 #个人博客 #语义搜索 #嵌入模型 #Qwen3 #AI推理 #媒体 #Anaconda配置云虚拟环境 #C语言 #vivado license #jupyter #WinSCP 下载安装教程 #SFTP #FTP工具 #服务器文件传输 #可信计算技术 #winscp #Shiro #反序列化漏洞 #CVE-2016-4437 #Nacos # 双因素认证 #运营 #React安全 #漏洞分析 #Next.js #python学习路线 #python基础 #python进阶 #python标准库 #powerbi #go #数据结构与算法 #嵌入式编译 #ccache #distcc #职场发展 #cursor #puppeteer #高仿永硕E盘的个人网盘系统源码 #汽车 #ICPC #ip #仙盟创梦IDE #东方仙盟 #运维工具 #YOLOFuse # Base64编码 # 多模态检测 #IPv6 #DNS #农产品物流管理 #物流管理系统 #农产品物流系统 #农产品物流 #动态规划 #xss #Discord机器人 #云部署 #程序那些事 #dlms #dlms协议 #逻辑设备 #逻辑设置间权限 #安全威胁分析 #源码 #闲置物品交易系统 #TRO #TRO侵权 #TRO和解 #claude-code #软件开发 #Minecraft #Minecraft服务器 #PaperMC #我的世界服务器 #ipmitool #BMC #未加引号服务路径 # 黑屏模式 # TTS服务器 #html5 #前端开发 #EN4FE #C #领域驱动 #VSCode # SSH #自由表达演说平台 #演说 #移动端h5网页 #调用浏览器摄像头并拍照 #开启摄像头权限 #拍照后查看与上传服务器端 #摄像头黑屏打不开问题 #nfs #iscsi #AI Agent #开发者工具 #SPA #单页应用 #web3.py #dash #swagger #kong #Kong Audio #Kong Audio3 #KongAudio3 #空音3 #空音 #中国民乐 #范式 #入侵 #日志排查 #创业管理 #财务管理 #团队协作 #创始人必修课 #数字化决策 #经营管理 #麒麟OS #文件管理 #文件服务器 #国产开源制品管理工具 #Hadess #一文上手 #卷积神经网络 #mariadb #结构与算法 # 大模型 # 模型训练 #ET模式 #非阻塞 #高并发服务器 #区间dp #二进制枚举 #图论 #工程实践 #pve #扩展屏应用开发 #android runtime #域名注册 #新媒体运营 #网站建设 #国外域名 #CLI #JavaScript #langgraph.json #TLS协议 #HTTPS #漏洞修复 #运维安全 #DDD #tdd #图像识别 #postman #easyui #大学生 #大作业 #raid #raid阵列 #KMS激活 # GPU服务器 # tmux #gpt #API #taro #ambari #bigtop #hdp #hue #kerberos #esp32 #mosquito #CSDN #效率神器 #办公技巧 #自动化工具 #Windows技巧 #打工人必备 #智能体从0到1 #新手入门 #欧拉 #webpack #儿童AI #图像生成 #kmeans #数字孪生 #三维可视化 # 远程开发 # Qwen3Guard-Gen-8B #SQL调优 #EXPLAIN #慢查询日志 #分布式架构 #后端开发 #Syslog #系统日志 #日志分析 #日志监控 #生产服务器问题查询 #日志过滤 #树莓派 #N8N # 水冷服务器 # 风冷服务器 #VoxCPM-1.5-TTS # 云端GPU # PyCharm宕机 #随机森林 #材料工程 #智能电视 #AI生成 # outputs目录 # 自动化 #stl #IIS Crypto #blender #warp #WinDbg #Windows调试 #内存转储分析 #AI+ #coze #AI入门 #AI赋能 #计组 #数电 #libosinfo #Go并发 #高并发架构 #Goroutine #系统设计 #Dify #鲲鹏 #net core #kestrel #web-server #asp.net-core #运维 #elk #esp32 arduino #AI视频创作系统 #AI视频创作 #AI创作系统 #AI视频生成 #AI工具 #AI创作工具 #HistoryServer #Spark #YARN #jobhistory #FASTMCP #sglang #夏天云 #夏天云数据 #ZooKeeper #ZooKeeper面试题 #面试宝典 #深入解析 #hdfs #大模型部署 #mindie #大模型推理 #华为od #华为od机试 #华为od机考 #华为od最新上机考试题库 #华为OD题库 #华为OD机试双机位C卷 #od机考题库 #ComfyUI # 推理服务器 #知识图谱 #React #Next #CVE-2025-55182 #RSC #UEFI #BIOS #Legacy BIOS #产品运营 #内存接口 # 澜起科技 # 服务器主板 #Puppet # IndexTTS2 # TTS #视频 #模拟退火算法 #Python3.11 #三维重建 #高斯溅射 #KMS 激活 #AI智能棋盘 #Rock Pi S #wireshark #x86_64 #数字人系统 #MC群组服务器 #windows11 #系统修复 #clawdbot #上下文工程 #langgraph #意图识别 #文件传输 #电脑文件传输 #电脑传输文件 #电脑怎么传输文件到另一台电脑 #电脑传输文件到另一台电脑 #说话人验证 #声纹识别 #CAM++ #云开发 #单例模式 #快递盒检测检测系统 #性能 #优化 #RAM #PTP_1588 #gPTP #ESP32 #传感器 #MicroPython #rtsp #转发 #WRF #WRFDA #unix #百度 #css3 #HarmonyOS #CS2 #debian13 #BoringSSL #数据采集 #浏览器指纹 #vertx #vert.x #vertx4 #runOnContext #视觉检测 #RXT4090显卡 #RTX4090 #深度学习服务器 #硬件选型 #网络配置实战 #Web/FTP 服务访问 #计算机网络实验 #外网访问内网服务器 #Cisco 路由器配置 #静态端口映射 #网络运维 #gitea #防火墙 # ARM服务器 # 鲲鹏 #IntelliJ IDEA #neo4j #NoSQL #SQL #http头信息 #Llama-Factory # 大模型推理 #k8s #gRPC #注册中心 #Tokio #异步编程 #系统编程 #Pin #http服务器 #AutoDL使用教程 #AI大模型训练 #linux常用命令 #PaddleOCR训练 #edge #迭代器模式 #观察者模式 #机器人学习 #Windows #CosyVoice3 # IP配置 # 0.0.0.0 #turn #ICE #信创国产化 #达梦数据库 #进程等待 #wait #waitpid #温湿度监控 #WhatsApp通知 #IoT #MySQL # 服务器IP # 端口7860 # 离线AI #万悟 #联通元景 #TCP服务器 #开发实战 #SMARC #ARM # 代理转发 #idm #网站 #截图工具 #批量处理图片 #图片格式转换 #图片裁剪 #健康医疗 #教育电商 #勒索病毒 #勒索软件 #加密算法 #.bixi勒索病毒 #数据加密 #OPCUA #CA证书 #健身房预约系统 #健身房管理系统 #健身管理系统 #web服务器 #渗透测试 #黑客技术 #文件上传漏洞 #ThingsBoard MCP #Kylin-Server #国产操作系统 #服务器安装 #Android16 #音频性能实战 #音频进阶 #短剧 #短剧小程序 #短剧系统 #微剧 #LangFlow # 智能运维 # 性能瓶颈分析 #hibernate #nosql # 云服务器 #科普 #CTF #agentic bi #gateway #Comate #遛狗 #论文复现 #sql注入 #uv #bug #网络编程 #I/O模型 #并发 #水平触发、边缘触发 #多路复用 #Host #SSRF #知识 #娱乐 #计算机毕业设计 #程序定制 #毕设代做 #课设 #SSH复用 #华为od机考真题 #华为od机试真题 #华为OD上机考试真题 #华为OD上机考试双机位C卷 #华为ODFLASH坏块监测系统 #C++ UA Server #SDK #跨平台开发 #osg #聊天小程序 #eclipse #arm64 #outlook #错误代码2603 #无网络连接 #2603 #注入漏洞 #cocos2d #图形渲染 #AI技术 #MOXA #学术生涯规划 #CCF目录 #基金申请 #职称评定 #论文发表 #科研评价 #顶会顶刊 #GATT服务器 #蓝牙低功耗 #服务器解析漏洞 #nodejs #UOS #海光K100 #统信 #NFC #智能公交 #服务器计费 #FP-增长 #具身智能 #moltbot #练习 #基础练习 #循环 #九九乘法表 #计算机实现 #esb接口 #走处理类报异常 #IT #技术 #safari #ARM64 # DDColor # ComfyUI #节日 #ESP32编译服务器 #Ping #DNS域名解析 #Kuikly #openharmony #le audio #低功耗音频 #通信 #连接 #部署 #地理 #遥感 #昇腾300I DUO #reactor反应堆 #面向对象 #smtp #smtp服务器 #PHP #intellij idea #rustdesk # REST API # keep-alive #cosmic #vnstat #c++20 # 远程连接 #clamav #fs7TF #实在Agent #UDP #攻防演练 #Java web #红队 #榛樿鍒嗙被 #昇腾 #npu #远程软件 #SSH跳板机 # Python3.11 #WT-2026-0001 #QVD-2026-4572 #smartermail #API限流 # 频率限制 # 令牌桶算法 #TTS私有化 # 音色克隆 #处理器 #CNAS #CMA #程序文件 #ansys #ansys问题解决办法 #黑群晖 #无U盘 #纯小白 #CPU #监测 #GB28181 #SIP信令 #SpringBoot #视频监控 # Connection refused #teamviewer #蓝湖 #Axure原型发布 #OSS #分库分表 #垂直分库 #水平分表 #雪花算法 #分布式ID #跨库查询 #分布式数据库 #集中式数据库 #业务需求 #选型误 #门禁 #梯控 #智能梯控 #Socket网络编程 #工作 #网安应急响应 # 硬件配置 #思维模型 #认知框架 #认知 #算力一体机 #ai算力服务器 #微PE # GLM # 服务连通性 #青少年编程 #Apple AI #Apple 人工智能 #FoundationModel #Summarize #SwiftUI #考试系统 #在线考试 #培训考试 #考试练习 #muduo库 #寄存器 #uvx #uv pip #npx #Ruff # 服务器配置 # GPU # 高并发 #数据恢复 #视频恢复 #视频修复 #RAID5恢复 #流媒体服务器恢复 #vrrp #脑裂 #keepalived主备 #高可用主备都持有VIP #coffeescript #SMP(软件制作平台) #EOM(企业经营模型) #应用系统 #服务器开启 TLS v1.2 #IISCrypto 使用教程 #TLS 协议配置 #IIS 安全设置 #服务器运维工具 #tornado # 轻量化镜像 # 边缘计算 #H3C #milvus #知识库 #web server #请求处理流程 # 批量部署 #copilot #RSO #机器人操作系统 #学工管理系统 #学工一体化平台 #学工软件二次开发 #学工平台定制开发 #学工系统服务商 #学工系统源头厂家 #智慧校园学工系统 #mtgsig #美团医药 #美团医药mtgsig #美团医药mtgsig1.2 #opc模拟服务器 #vmware #MQTT协议 #CVE-2025-68143 #CVE-2025-68144 #CVE-2025-68145 #Socket #套接字 #I/O多路复用 #字节序 #reactjs #weston #x11 #x11显示服务器 #语音生成 #TTS #网络攻击模型 #集成学习 #cocoa #tcp/ip #网络 #证书 # ms-swift #服务器线程 # SSL通信 # 动态结构体 #因果学习 #政务 # 数字人系统 # 远程部署 #Tetrazine-Acid #1380500-92-4 #1panel #个人助理 #数字员工 #JNI #漏洞挖掘 #Exchange #sentinel #KMS #slmgr #阳台种菜 #园艺手扎 #Gemini #Nano Banana Pro #宝塔面板部署RustDesk #RustDesk远程控制手机 #手机远程控制 #汇编 #可再生能源 #绿色算力 #风电 #连接数据库报错 #高精度农业气象 #递归 #线性dp #POC #问答 #交付 #pyqt #webgl #AI应用编程 # 自动化运维 #Ward #r语言 #IPMI #运动 #文本生成 #CPU推理 #4U8卡 AI 服务器 ##AI 服务器选型指南 #GPU 互联 #GPU算力 #ShaderGraph #图形 #日志模块 #STDIO传输 #SSE传输 #WebMVC #WebFlux #VMware Workstation16 #服务器操作系统 #音诺ai翻译机 #AI翻译机 # Ampere Altra Max #服务器IO模型 #非阻塞轮询模型 #多任务并发模型 #异步信号模型 #多路复用模型 #边缘AI # Kontron # SMARC-sAMX8 #ueditor导入word #ueditor导入pdf #代理模式 #Spring AOP #scanf #printf #getchar #putchar #cin #cout #xml #remote-ssh #小艺 #搜索 #Smokeping #GPU #租显卡 #训练推理 #投标 #标书制作 #AI应用 #多进程 #python技巧 #高考 #企业级存储 #网络设备 #多模态 #微调 #超参 #LLamafactory #题解 #图 #dijkstra #迪杰斯特拉 #麒麟 #V11 #kylinos #大模型应用 #API调用 #PyInstaller打包运行 #服务端部署 #程序开发 #程序设计 #mvc #Linux多线程 #idc #Java程序员 #Java面试 #Spring源码 #zotero #WebDAV #同步失败 #轻量化 #低配服务器 #NSP #下一状态预测 #aigc #信息收集 #Langchain-Chatchat # 国产化服务器 # 信创 #智能制造 #供应链管理 #工业工程 #库存管理 #量子计算 #RK3588 #RK3588J #评估板 #核心板 #嵌入式开发 # 模型微调 #Autodl私有云 #深度服务器配置 #旅游 #.netcore #提词器 #实体经济 #商业模式 #数智红包 #商业变革 #创业干货 #西门子 #汇川 #Blazor #经济学 #zygote #应用进程 #VMware创建虚拟机 #挖漏洞 #攻击溯源 #编程 #晶振 #n8n解惑 #resnet50 #分类识别训练 #m3u8 #HLS #移动端H5网页 #APP安卓苹果ios #监控画面 直播视频流 #SSH代理转发 #Zabbix #语音合成 #OpenManage #Spire.Office #隐私合规 #网络安全保险 #法律风险 #风险管理 #企业微信机器人 #本地大模型 #Xshell #Finalshell #生物信息学 #组学 #统信UOS #win10 #qemu #QQbot #QQ #广播 #组播 #并发服务器 # 服务器迁移 # 回滚方案 #身体实验室 #健康认知重构 #微行动 #NEAT效应 #亚健康自救 #ICT人 #eureka #c++高并发 #百万并发 #Termux #Samba #公共MQTT服务器 #企业存储 #RustFS #对象存储 #高可用 #三维 #3D #云计算运维 #asp.net上传大文件 #0day漏洞 #DDoS攻击 #漏洞排查 #uip #Coturn #懒汉式 #恶汉式 #win11 #模块 # DIY主机 # 交叉编译 #CVE-2025-61686 #路径遍历高危漏洞 #路由器 #Redis #分布式锁 #全文检索 #银河麒麟服务器系统 #服务器架构 #AI推理芯片 #视觉理解 #Moondream2 #多模态AI #c ##租显卡 #devops #CS336 #Assignment #Experiments #TinyStories #Ablation #实时音视频 # GPU租赁 # 自建服务器 #余行补位 #意义对谈 #余行论 #领导者定义计划 #数据访问 #H5网页 #网页白屏 #H5页面空白 #资源加载问题 #打包部署后网页打不开 #HBuilderX #星际航行 #A2A #GenAI #VMWare Tool #MinIO服务器启动与配置详解 #AE #磁盘配额 #存储管理 #形考作业 #国家开放大学 #系统运维 #DHCP #网络安全大赛 #ARMv8 #内存模型 #内存屏障 #mssql #实时检测 #DAG #AITechLab #cpp-python #CUDA版本 #云服务器选购 #Saas #SSH密钥 # ControlMaster #设计规范 #放大电路 #HarmonyOS APP #b树 #期刊 #SCI #基础语法 #标识符 #常量与变量 #数据类型 #运算符与表达式 #memory mcp #Cursor #数据可视化 #智能体来了 #网路编程 #docker-compose #声源定位 #MUSIC #游戏服务器断线 #AI电商客服 #Buck #NVIDIA #交错并联 #DGX #百度文库 #爱企查 #旋转验证码 #验证码识别 #主板 #总体设计 #电源树 #框图 #Archcraft #Linly-Talker # 数字人 # 服务器稳定性 #memcache #ServBay #语义检索 #向量嵌入 #C2000 #TI #实时控制MCU #AI服务器电源 # 树莓派 # ARM架构 #传统行业 #gerrit #AI 推理 #NV #glances # OTA升级 # 黄山派 #内网 #人脸活体检测 #live-pusher #动作引导 #张嘴眨眼摇头 #苹果ios安卓完美兼容 # 网络延迟 #gnu #ranger #MySQL8.0 #智能体对传统行业冲击 #行业转型 #系统管理 #服务 #代理服务器 #duckdb #强化学习 #策略梯度 #REINFORCE #蒙特卡洛 #screen命令 #claudeCode #content7 #cesium #可视化 #超时设置 #客户端/服务器 #挖矿 #Linux病毒 #管道Pipe #system V #odoo #阿里云RDS #雨云服务器 #教程 #MCSM面板 #appche #LED #设备树 #GPIO #muduo #TcpServer #accept #软件需求 #ftp #sftp #AI-native #国产化OS #华为机试 #OpenHarmony #samba # 批量管理 #Aluminium #Google #ASR #SenseVoice #硬盘克隆 #DiskGenius # 键鼠锁定 #工程设计 #预混 #扩散 #燃烧知识 #层流 #湍流 #计算几何 #斜率 #方向归一化 #叉积 #PN 结 #ArkUI #ArkTS #鸿蒙开发 #超算中心 #PBS #lsf #全栈 #反向代理 #报表制作 #职场 #用数据讲故事 #手机h5网页浏览器 #安卓app #苹果ios APP #手机电脑开启摄像头并排查 #参数估计 #矩估计 #概率论 #MCP服务器注解 #异步支持 #方法筛选 #声明式编程 #自动筛选机制 #传媒 #pxe #CCE #Dify-LLM #Flexus #隐函数 #常微分方程 #偏微分方程 #线性微分方程 #线性方程组 #非线性方程组 #复变函数 #gmssh #宝塔 #计算机现代史 #系统安装 #铁路桥梁 #DIC技术 #箱梁试验 #裂纹监测 #四点弯曲 #UDP服务器 #recvfrom函数 #MinIO #麦克风权限 #访问麦克风并录制音频 #麦克风录制音频后在线播放 #用户拒绝访问麦克风权限怎么办 #uniapp 安卓 苹果ios #将音频保存本地或上传服务器 #一人公司 #独立开发者 #scikit-learn #思爱普 #SAP S/4HANA #ABAP #NetWeaver #WAN2.2 #sklearn #okhttp #人形机器人 #人机交互 #EventLoop #人大金仓 #Kingbase #统信操作系统 #字符串 #时间复杂度 #空间复杂度 #OpenAI #故障 #电梯 #电梯运力 #电梯门禁 #bond #服务器链路聚合 #网卡绑定 #数据报系统 #Beidou #北斗 #SSR #docker安装seata #poll #numpy #编程语言 # AI部署 #人脸识别sdk #视频编解码 #远程更新 #缓存更新 #多指令适配 #物料关联计划 #防毒面罩 #防尘面罩 #编程助手 #江协 #瑞萨 #OLED屏幕移植 #Prometheus #决策树 #二值化 #Canny边缘检测 #轮廓检测 #透视变换 #图像分类 #图像分割 #yolo26算法 #DooTask #交换机 #三层交换机 #2025年 #开关电源 #热敏电阻 #PTC热敏电阻 #AI工具集成 #容器化部署 #个人电脑 #AI教程 #Matrox MIL #二次开发 #CMC #一周会议与活动 #ICLR #CCF #自动化巡检 #SQL注入主机 # 权限修复 #istio #服务发现 #戴尔服务器 #戴尔730 #装系统 #junit #SEW #赛威 #SEW变频器 #vncdotool #链接VNC服务器 #如何隐藏光标 #rag #FHSS #ossinsight #算力建设 #canvas层级太高 #canvas遮挡问题 #盖住其他元素 #苹果ios手机 #安卓手机 #调整画布层级 #测速 #iperf #iperf3 #lucene #分子动力学 #化工仿真 #小智 #ETL管道 #向量存储 #数据预处理 #DocumentReader #spring ai #oauth2 #nmodbus4类库使用教程 # 高温监控 # 环境迁移 #电子电气架构 #系统工程与系统架构的内涵 #Routine #starrocks #Taiji #STL #string #格式工厂 #L6 #L10 #L9 # 串口服务器 # NPort5630 #composer #symfony #java-zookeeper #uniapp #合法域名校验出错 #服务器域名配置不生效 #request域名配置 #已经配置好了但还是报错 #uniapp微信小程序 #C₃₂H₄₅N₇O₁₁S₂ #Gateway #认证服务器集成详解 #proc #cpu #个性化推荐 #BERT模型 #pipeline #Transformers #NLP #Qwen3-VL # 服务状态监控 # 视觉语言模型 #后端框架 #AI运维 #DevOps自动化 #RWK35xx #语音流 #实时传输 #node #adobe #数据迁移 #free #vmstat #sar #express #cherry studio # child_process #计算机外设 #Arduino BLDC #核辐射区域探测机器人 #基金 #股票 #jquery #fork函数 #进程创建 #进程终止 #session #JADX-AI 插件 #api #key #AI作画 #boltbot #xshell #host key #rsync # 数据同步 #YOLO识别 #YOLO环境搭建Windows #YOLO环境搭建Ubuntu #Python办公自动化 #Python办公 #DuckDB #协议 #tekton