news 2026/8/13 12:36:24

Python图片爬虫实战:从Requests到异步下载的完整实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python图片爬虫实战:从Requests到异步下载的完整实现

1. 项目概述:从手动右键到自动化归档

干过内容运营、素材收集或者数据分析的朋友,十有八九都遇到过这个场景:看到一个网页,里面几十上百张高清图片,正是你急需的素材库。然后呢?一张张右键、另存为、重命名……重复劳动枯燥不说,还容易出错漏存。几年前我刚入行做新媒体时,就经常为了找配图这么干,效率低到令人发指。后来接触了Python,第一个想到的自动化任务就是搞定这个痛点——写个爬虫,让它替我批量抓取网页上的图片并保存到本地。

这个项目,说白了就是用程序模拟浏览器访问网页,自动识别页面中的所有图片链接,然后一张张下载下来,并按你设定的规则整理好。它解决的远不止是“省时间”的问题。比如,在做竞品分析时,你需要批量抓取对手官网的产品图;在做设计灵感收集时,需要从特定网站归档一批风格统一的图片;甚至在做简单的数据标注或图像识别项目前期,也需要一个可靠的图片采集工具。手动操作在几十张的规模下尚可忍受,一旦目标成百上千,自动化就成了唯一可行的路径。

实现这个目标,核心就是Python。它丰富的第三方库,让HTTP请求、HTML解析、文件操作这些步骤变得异常简单。即使你是个刚学完基础语法的新手,跟着清晰的步骤走,一两个小时也能搭出一个可用的爬虫。接下来,我会结合我这些年踩过的坑和优化经验,把一个完整的、健壮的图片爬虫从思路到代码,再到部署和问题排查,给你彻底讲明白。你会发现,自动化处理信息,才是打开数字世界效率之门的正确方式。

2. 核心工具链选型与原理剖析

工欲善其事,必先利其器。选对工具,项目就成功了一半。一个图片爬虫的工作流程可以抽象为四个核心环节:获取网页、解析内容、提取链接、下载保存。每个环节都有若干成熟的Python库可供选择,我们的选型需要兼顾易用性、性能和生态。

2.1 网络请求库:Requests vs. aiohttp

首先是把网页的原始HTML代码“拿回来”。这里最经典的选择是requests库。它提供了极其人性化的API,几乎成了Python发送HTTP请求的事实标准。它的优点是同步、阻塞式,代码写起来是线性的,非常易于理解和调试。对于初学者或者目标页面不多的场景,requests是首选。

import requests response = requests.get('https://example.com') html_content = response.text

但是,当需要批量抓取成百上千个页面,或者一个页面里有大量图片时,同步请求的缺点就暴露了:你必须等一张图片下载完,才能开始下一张,大部分时间都在等待网络I/O,CPU是空闲的。这时,异步库aiohttp配合asyncio就该登场了。它可以同时发起和处理大量网络请求,极大地提升下载效率。不过,异步编程模型有一定学习门槛,代码结构也更复杂。

实操心得:对于新手,强烈建议从requests开始。先把同步的逻辑跑通,理解整个流程。当你的爬虫需要抓取的图片量很大,并且遇到了明显的性能瓶颈时,再考虑升级到aiohttp。99%的中小规模需求,requests完全够用。

2.2 HTML解析库:BeautifulSoup4 与 lxml

拿到HTML后,我们需要从中“大海捞针”,找出所有图片的标签(通常是<img>)。这就需要HTML解析库。BeautifulSoup4(简称bs4)是这方面的王者,它提供了“一锅乱炖”式的解析方式,能很好地处理各种不规范的HTML,API也非常直观,支持通过标签名、属性、CSS选择器等多种方式查找元素。

from bs4 import BeautifulSoup soup = BeautifulSoup(html_content, 'html.parser') img_tags = soup.find_all('img')

注意上面代码中的'html.parser',这是Python内置的解析器,速度慢但无需安装。在实际生产中,我们通常会指定'lxml'作为解析器(需要先pip install lxml)。lxml是一个用C语言编写的库,解析速度极快,容错能力也更强。BeautifulSoup只是一个“包装器”,它依赖底层的解析器(如lxml,html5lib)来干活。所以,最佳实践是安装lxml,然后这样创建对象:

soup = BeautifulSoup(html_content, 'lxml') # 速度更快,更健壮

2.3 图片链接提取与下载

找到<img>标签后,图片的URL通常存储在src属性里。但事情没那么简单。有些网站使用懒加载技术,初始的src可能是一个占位图,真正的图片URL藏在>环节首选工具备选/进阶工具核心作用网络请求requestsaiohttp(异步)获取网页HTML内容HTML解析BeautifulSoup4+lxmlparsel(Scrapy风格)从HTML中定位<img>标签链接提取BeautifulSoup属性查找正则表达式re从标签中获取真实的图片URL文件下载requests.get()(流模式)aiohttp+aiofiles(异步)将网络图片以二进制形式保存到磁盘路径管理os,pathlib-创建目录、生成文件名、管理文件

这套组合拳,构成了我们爬虫项目的技术骨架。接下来,我们就用它们来搭建一个五脏俱全的爬虫。

3. 基础爬虫搭建:从零到一的完整实现

让我们暂时忘掉那些复杂的概念,先动手实现一个最基础、但绝对可用的版本。这个版本的目标很明确:给定一个网页URL,爬取该页面上所有图片,保存到本地一个文件夹里。

3.1 环境准备与依赖安装

首先,确保你的Python环境已经就绪(建议使用Python 3.7及以上版本)。然后,通过pip安装我们需要的核心库。打开你的终端或命令行,执行以下命令:

pip install requests beautifulsoup4 lxml

这三行命令会安装网络请求、HTML解析以及高效的解析器引擎。安装过程通常很快,如果遇到速度慢的问题,可以考虑使用国内的镜像源,例如加上-i https://pypi.tuna.tsinghua.edu.cn/simple

3.2 核心代码逐行解析

下面,我们创建一个名为simple_image_crawler.py的Python文件,并开始编写代码。

第一步:导入必要的模块

import os import requests from bs4 import BeautifulSoup from urllib.parse import urljoin, urlparse
  • os: 用于操作系统功能,如创建目录。
  • requests: 用于发送HTTP请求。
  • BeautifulSoup: 用于解析HTML。
  • urllib.parse.urljoin: 这是一个至关重要的函数。网页中的图片链接很多是相对路径(如/images/photo.jpg),我们需要将其与基础URL拼接成绝对路径。
  • urllib.parse.urlparse: 用于解析URL,从中提取信息,比如我们用它来生成合理的本地文件名。

第二步:定义核心爬取函数

def download_images(url, save_dir='downloaded_images'): """ 从指定URL下载所有图片到本地目录 :param url: 目标网页的URL :param save_dir: 图片保存的本地目录名 """ # 1. 创建保存目录 if not os.path.exists(save_dir): os.makedirs(save_dir) print(f"[信息] 创建保存目录: {save_dir}") else: print(f"[信息] 目录已存在: {save_dir}") # 2. 发送HTTP请求,获取网页内容 try: 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(url, headers=headers, timeout=10) response.raise_for_status() # 如果状态码不是200,抛出异常 response.encoding = response.apparent_encoding # 自动识别编码 html_content = response.text except requests.exceptions.RequestException as e: print(f"[错误] 请求网页失败: {e}") return # 3. 解析HTML,找到所有img标签 soup = BeautifulSoup(html_content, 'lxml') img_tags = soup.find_all('img') print(f"[信息] 在页面上找到 {len(img_tags)} 个图片标签") # 4. 遍历每个img标签,下载图片 downloaded_count = 0 for i, img_tag in enumerate(img_tags): # 获取图片链接。优先考虑>if __name__ == '__main__': target_url = 'https://example.com' # 替换成你想爬取的网站 download_images(target_url)

3.3 代码关键点解读与避坑指南

  1. User-Agent头:这是模拟浏览器访问的关键。没有这个头,很多网站会拒绝请求或返回不同的内容。代码中使用的是一个常见的Chrome浏览器UA字符串。
  2. 异常处理:网络请求和文件操作充满了不确定性。使用try...except包裹关键步骤,可以避免程序因单个图片下载失败而整体崩溃。
  3. 链接补全urljoin(base, url)是处理相对路径的神器。无论img_url/img/1.jpg还是./img/1.jpg,它都能正确拼接成完整的URL。
  4. 流式下载requests.get(stream=True)配合iter_content()可以分块下载大文件,避免一次性将整个图片加载到内存,更安全高效。
  5. 文件名处理:直接从URL路径的最后一部分取文件名是最常见的做法。但必须考虑文件名可能缺失、包含非法字符或重复的情况。我们的代码做了简单的冲突处理。
  6. 懒加载处理img_tag.get('data-src') or img_tag.get('src')这行代码是关键。它优先获取>headers = { 'User-Agent': '...', 'Referer': 'https://www.google.com/', # 示例,可设置为目标网站的域名 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', }
  7. 请求延迟:在循环下载图片的请求之间,随机等待一小段时间。这是最基本的“礼貌”,可以避免因请求过快被服务器封禁IP。

    import time import random # 在下载每张图片的循环内,请求前或请求后添加 time.sleep(random.uniform(0.5, 2.0)) # 随机等待0.5到2秒
  8. 处理Cookie与Session:有些网站需要登录后才能看到图片。这时可以使用requests.Session()对象,它会自动管理Cookie,模拟一次完整的浏览器会话。

    session = requests.Session() # 可以先POST请求登录(如果需要) # login_data = {'username': '...', 'password': '...'} # session.post(login_url, data=login_data) # 然后用session去get目标页面 response = session.get(target_url, headers=headers)

4.2 增强链接提取与过滤

基础版本只抓取了<img>标签。但图片还可能以其他形式存在:

  1. CSS背景图:有些图片通过background-image: url(...)设置在CSS里。要抓取这些,需要先提取所有<style>标签或链接的CSS文件,然后用正则表达式匹配url(...)中的路径。这比较复杂,通常需要根据目标网站具体情况定制。
  2. JavaScript动态加载:越来越多的网站用JS动态渲染内容,初始HTML里没有图片标签。这时requests+BeautifulSoup就无能为力了,因为它们只能看到JS执行前的静态HTML。解决方案是使用SeleniumPlaywright这类浏览器自动化工具,它们能控制一个真实的浏览器(如Chrome)加载页面、执行JS,等页面完全渲染后再获取HTML。这是一个更高级的话题,代码复杂度和资源消耗也更大。
  3. 链接过滤:我们可能只想要特定尺寸、特定格式的图片。可以在提取链接后增加过滤逻辑。
    # 示例:只下载jpg和png格式,且链接中包含‘large’关键词的图片 allowed_extensions = ('.jpg', '.jpeg', '.png', '.webp') if not img_url.lower().endswith(allowed_extensions): continue if 'large' not in img_url: # 这是一个简单示例,实际规则更复杂 continue

4.3 文件管理优化

  1. 按域名或日期分类保存:下载的图片全部堆在一个文件夹里,很快就会混乱。我们可以创建更有条理的目录结构。

    import datetime # 在创建保存目录时,使用更结构化的路径 domain = urlparse(url).netloc.replace('www.', '') # 获取域名,去掉www date_str = datetime.datetime.now().strftime('%Y%m%d') save_dir = os.path.join('downloads', domain, date_str) # 最终路径如: downloads/example.com/20231027/
  2. 更智能的文件命名:除了从URL提取,我们还可以尝试从图片标签的alt属性(图片描述文本)生成文件名,或者使用MD5哈希值作为唯一文件名。

    import hashlib # 使用图片内容的MD5作为文件名,绝对唯一 img_data = img_response.content file_hash = hashlib.md5(img_data).hexdigest() # 获取文件扩展名 content_type = img_response.headers.get('content-type', '') if 'jpeg' in content_type: ext = '.jpg' elif 'png' in content_type: ext = '.png' else: # 从URL猜测,或使用默认 ext = '.jpg' filename = f'{file_hash}{ext}'

4.4 加入进度显示与日志记录

对于批量下载,一个直观的进度条能极大提升体验。可以使用tqdm库。

pip install tqdm
from tqdm import tqdm # 将遍历 img_tags 的循环改为 for i, img_tag in enumerate(tqdm(img_tags, desc="下载进度")): # ... 下载逻辑 ...

同时,将打印信息写入日志文件,方便事后排查问题。

import logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[logging.FileHandler('crawler.log'), logging.StreamHandler()]) # 之后用 logging.info(...) 代替 print(...)

经过这些增强,你的爬虫已经从一个“玩具”升级为一个相对可靠的工具了。它更礼貌、更健壮、也更易用。

5. 实战:构建一个可配置的通用爬虫脚本

现在,我们把前面提到的所有最佳实践整合起来,写一个更通用、更强大的爬虫脚本。这个脚本支持通过命令行参数配置,并具备基本的错误恢复能力。

创建一个新文件advanced_image_crawler.py

#!/usr/bin/env python3 """ 高级图片爬虫脚本 支持命令行参数,具备反爬、分类保存、日志记录等功能。 """ import os import sys import time import random import logging import argparse import hashlib from urllib.parse import urljoin, urlparse from concurrent.futures import ThreadPoolExecutor, as_completed import requests from bs4 import BeautifulSoup from tqdm import tqdm # 配置日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s', handlers=[ logging.FileHandler('image_crawler.log', encoding='utf-8'), logging.StreamHandler(sys.stdout) ] ) logger = logging.getLogger(__name__) class ImageCrawler: def __init__(self, base_url, output_dir='./downloaded_images', max_workers=5, delay_range=(1, 3)): """ 初始化爬虫 :param base_url: 目标网页URL :param output_dir: 输出根目录 :param max_workers: 并发下载线程数 :param delay_range: 请求延迟范围(秒) """ self.base_url = base_url self.output_dir = output_dir self.max_workers = max_workers self.delay_range = delay_range # 创建按域名和日期分类的目录 self.domain = urlparse(base_url).netloc.replace('www.', '') self.date_str = time.strftime('%Y%m%d') self.save_dir = os.path.join(output_dir, self.domain, self.date_str) os.makedirs(self.save_dir, exist_ok=True) logger.info(f"图片将保存至: {self.save_dir}") # 会话和请求头 self.session = requests.Session() self.headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', 'Referer': base_url, } # 记录已下载的图片哈希,避免重复下载(同一页面内) self.downloaded_hashes = set() def _random_delay(self): """随机延迟,模拟人工操作""" time.sleep(random.uniform(*self.delay_range)) def fetch_page(self): """获取目标页面HTML""" try: logger.info(f"正在获取页面: {self.base_url}") self._random_delay() resp = self.session.get(self.base_url, headers=self.headers, timeout=15) resp.raise_for_status() # 尝试自动检测编码 resp.encoding = resp.apparent_encoding if resp.apparent_encoding else 'utf-8' return resp.text except requests.exceptions.RequestException as e: logger.error(f"获取页面失败: {e}") return None def extract_image_urls(self, html): """从HTML中提取所有图片URL""" if not html: return [] soup = BeautifulSoup(html, 'lxml') img_tags = soup.find_all('img') urls = [] for img in img_tags: # 多种属性尝试 for attr in ['data-src', 'data-original', 'src', 'data-lazy-src']: img_url = img.get(attr) if img_url and not img_url.startswith('data:image'): # 排除base64内嵌图片 # 转换为绝对URL absolute_url = urljoin(self.base_url, img_url) urls.append(absolute_url) break # 找到一个有效属性就跳出循环 # 去重 unique_urls = list(dict.fromkeys(urls)) logger.info(f"共提取到 {len(unique_urls)} 个唯一图片链接") return unique_urls def download_single_image(self, img_url, index): """下载单张图片""" try: self._random_delay() resp = self.session.get(img_url, headers=self.headers, stream=True, timeout=20) resp.raise_for_status() # 根据Content-Type确定扩展名 content_type = resp.headers.get('content-type', '').lower() if 'jpeg' in content_type or 'jpg' in content_type: ext = '.jpg' elif 'png' in content_type: ext = '.png' elif 'gif' in content_type: ext = '.gif' elif 'webp' in content_type: ext = '.webp' else: # 从URL猜测,或使用默认 parsed = urlparse(img_url) path_ext = os.path.splitext(parsed.path)[1] ext = path_ext if path_ext and len(path_ext) < 6 else '.jpg' # 生成唯一文件名:索引_内容MD5 img_data = resp.content file_hash = hashlib.md5(img_data).hexdigest()[:8] # 取前8位,足够唯一且短 # 检查是否重复(基于哈希) if file_hash in self.downloaded_hashes: logger.warning(f"跳过重复图片: {img_url}") return False filename = f"{index:04d}_{file_hash}{ext}" filepath = os.path.join(self.save_dir, filename) with open(filepath, 'wb') as f: f.write(img_data) self.downloaded_hashes.add(file_hash) logger.debug(f"已保存: {filename}") return True except Exception as e: logger.error(f"下载失败 [{img_url[:50]}...]: {e}") return False def run(self): """主运行流程""" html = self.fetch_page() if not html: logger.error("无法获取页面内容,程序退出。") return image_urls = self.extract_image_urls(html) if not image_urls: logger.warning("未在页面中发现图片链接。") return logger.info(f"开始下载 {len(image_urls)} 张图片,使用 {self.max_workers} 个线程...") success_count = 0 # 使用线程池并发下载 with ThreadPoolExecutor(max_workers=self.max_workers) as executor: # 创建任务字典 {future: (url, index)} future_to_url = { executor.submit(self.download_single_image, url, idx): (url, idx) for idx, url in enumerate(image_urls, 1) } # 使用tqdm创建进度条 with tqdm(total=len(image_urls), desc="下载进度", unit="img") as pbar: for future in as_completed(future_to_url): url, idx = future_to_url[future] try: if future.result(): # 如果下载成功返回True success_count += 1 except Exception as e: logger.error(f"任务执行异常 [{url[:50]}...]: {e}") finally: pbar.update(1) # 更新进度条 logger.info(f"任务完成!成功下载 {success_count}/{len(image_urls)} 张图片。") logger.info(f"图片保存位置: {os.path.abspath(self.save_dir)}") def main(): parser = argparse.ArgumentParser(description='高级图片爬虫') parser.add_argument('url', help='目标网页的URL') parser.add_argument('-o', '--output', default='./downloaded_images', help='输出目录 (默认: ./downloaded_images)') parser.add_argument('-w', '--workers', type=int, default=5, help='并发下载线程数 (默认: 5)') parser.add_argument('-d', '--delay', type=float, nargs=2, default=[1.0, 3.0], metavar=('MIN', 'MAX'), help='请求延迟范围,单位秒 (默认: 1.0 3.0)') args = parser.parse_args() crawler = ImageCrawler( base_url=args.url, output_dir=args.output, max_workers=args.workers, delay_range=tuple(args.delay) ) crawler.run() if __name__ == '__main__': main()

这个脚本的亮点在于:

  1. 面向对象封装:将功能封装在ImageCrawler类中,结构清晰,易于维护和扩展。
  2. 命令行接口:使用argparse库,可以通过命令行参数灵活配置URL、输出目录、并发数等。
  3. 并发下载:使用ThreadPoolExecutor实现多线程下载,显著提升批量下载速度。
  4. 智能去重:通过计算图片内容的MD5哈希值,避免下载完全相同的图片。
  5. 健壮的文件命名:结合索引和哈希值,生成唯一且有序的文件名。
  6. 完善的日志:同时输出到控制台和文件,便于调试和追溯。

使用方法:

# 基本用法 python advanced_image_crawler.py https://example.com # 指定输出目录和并发数 python advanced_image_crawler.py https://example.com -o ./my_pics -w 10 # 指定更长的请求延迟(更礼貌) python advanced_image_crawler.py https://example.com -d 2 5

6. 常见问题排查与实战经验分享

即使有了健壮的脚本,在实际操作中还是会遇到各种稀奇古怪的问题。下面是我总结的一些典型“坑”及其解决方案。

6.1 请求被拒绝或返回403错误

这是最常见的反爬虫响应。

  • 症状requests.get()抛出异常,或返回的状态码是403 Forbidden。
  • 排查与解决
    1. 检查User-Agent:确保你的请求头中包含一个常见浏览器的User-Agent。可以尝试更换不同的UA字符串。
    2. 添加Referer:有些网站会检查请求来源(Referer),将其设置为目标网站的域名或一个搜索引擎的URL。
    3. 使用Session:对于需要维持状态的网站,务必使用requests.Session()
    4. 模拟更完整的请求头:复制浏览器开发者工具中Network标签下的一个真实请求的所有Headers,直接用作你的请求头字典。
    5. 终极方案:Selenium:如果网站反爬极其严格(如验证码、复杂JS加密),考虑使用Selenium模拟真人操作。但这会牺牲速度。

6.2 下载的图片文件损坏或无法打开

  • 症状:文件大小异常(如只有几KB),或用图片查看器打开时报错。
  • 排查与解决
    1. 检查响应状态码和内容类型:在保存文件前,打印resp.status_coderesp.headers.get('content-type')。确保状态码是200,且内容类型是图片(如image/jpeg)。有时服务器返回的错误页面(如404 HTML)也被当成了图片内容。
    2. 检查流式下载:确保使用了stream=Trueresp.iter_content()。直接使用resp.content对于大文件可能引发内存问题,但通常不会导致文件损坏。
    3. 验证文件头:真正的图片文件有特定的文件头(Magic Number)。例如,JPEG以FF D8 FF开头,PNG以89 50 4E 47开头。可以写一个简单的函数在保存前校验。

6.3 爬取到的图片数量远少于浏览器所见

  • 症状:脚本只找到十几张图,但浏览器肉眼可见有上百张。
  • 排查与解决
    1. 懒加载(Lazy Load):这是最主要的原因。现代网站大量使用此技术。解决方案就是像我们代码里做的那样,优先抓取>import re def sanitize_filename(filename): # 移除非法字符 filename = re.sub(r'[\/:*?"<>|]', '_', filename) # 限制长度(可选) if len(filename) > 255: name, ext = os.path.splitext(filename) filename = name[:250-len(ext)] + ext return filename

6.5 性能瓶颈与优化

  • 症状:下载几百张图片速度极慢。
  • 优化方向
    1. 增加并发:如我们脚本中所做,使用线程池(ThreadPoolExecutor)。注意,线程数不是越多越好,一般设置为5-15个为宜,过多可能导致本地网络拥堵或被目标服务器封禁。
    2. 异步IO:对于IO密集型任务,异步是终极方案。将核心下载逻辑用aiohttpaiofiles重写,可以同时处理成千上万个请求,性能提升巨大,但代码复杂度也最高。
    3. 减少延迟:在遵守网站规则的前提下,可以适当缩短delay_range。对于反爬不严的网站,可以设置为(0.1, 0.5)
    4. 连接复用:使用requests.Session()本身就复用了TCP连接,比每次创建新连接高效。

6.6 法律与道德风险规避

这是最重要的一点,技术必须在合规的框架内使用。

  • 尊重robots.txt:在爬取前,访问https://目标网站/robots.txt,查看是否允许爬虫访问你想要的路径。Python有robotparser模块可以解析此文件。
  • 控制请求速率:务必在请求间添加延迟,避免对目标服务器造成拒绝服务攻击(DoS)的压力。我们的_random_delay函数就是干这个的。
  • 遵守版权:明确你爬取的图片的版权归属。个人学习、研究使用通常属于合理使用范畴,但未经授权用于商业目的、大量分发或公开传播,可能构成侵权。
  • 识别并遵守网站条款:许多网站的“服务条款”(Terms of Service)中明确禁止爬虫。在使用自动化工具前,最好查阅一下。

最后,分享一个我自己的习惯:在运行任何爬虫,尤其是新写的、针对陌生网站的爬虫时,我会先用一个很小的、只抓取前2-3张图片的测试模式跑一遍。观察日志,检查下载的图片是否正确,请求是否正常。确认无误后,再放开限制进行全量爬取。这个习惯帮我避免了很多次“跑了一晚上,结果全下错了”的悲剧。爬虫开发,三分在写,七分在调。耐心和细致的测试,是成功的关键。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/13 12:35:46

AgentRun:构建生产级多智能体协作系统的架构设计与实践

1. 项目概述&#xff1a;从“单兵作战”到“集团军协同”的必然之路 如果你最近在折腾大模型应用&#xff0c;尤其是尝试过 LangChain、Dify 或者 Coze 这类平台来创建所谓的“智能体”&#xff0c;那你大概率经历过这样的场景&#xff1a;你精心设计了一个能写周报的智能体&am…

作者头像 李华
网站建设 2026/8/13 12:35:25

2026工业网络安全技术演进、防护体系搭建与产品选型实战指南

2026年&#xff0c;国内制造业数字化改造进入收尾与深化并行阶段。大量工厂完成了设备联网、产线上云、数据互通的基础建设&#xff0c;原本封闭隔离的工控网络&#xff0c;彻底打破了物理边界。传统工业安全依赖的物理隔离、简单防火墙、被动查杀模式&#xff0c;已经完全跟不…

作者头像 李华
网站建设 2026/8/13 12:32:31

还在为肝细胞系HepG2 CYP酶活显著降低而困扰?小鼠肝实质原代细胞,保留完整药物代谢功能

在药物代谢研究与肝毒性评价中&#xff0c;一个反复出现的困境正困扰着众多科研工作者&#xff1a;明明选择了肝脏来源的细胞模型&#xff0c;实验结果却总是与体内真实情况相去甚远。问题往往出在细胞模型本身——当你依赖HepG2细胞时&#xff0c;你可能已经在不知不觉中走上了…

作者头像 李华
网站建设 2026/8/13 12:31:11

开发者的 AI 大模型百科全书:Model.zoz.la

选模型这件事&#xff0c;不该这么难 你最近一次为了对比两个 AI 模型的上下文窗口、定价、支持的功能&#xff0c;在多少个标签页之间来回切换&#xff1f; OpenAI 的文档看一眼&#xff0c;Anthropic 的定价页翻一翻&#xff0c;Google 的 Gemini 表格再查一查……等你终于…

作者头像 李华
网站建设 2026/8/13 12:30:06

基于STC15单片机的PS2手柄协议解析与USB转接实战

1. 项目概述&#xff1a;当经典手柄遇上国产MCU 最近在整理工作室的旧物&#xff0c;翻出了一个尘封已久的PS2原装手柄。看着那熟悉的造型和磨损的按键&#xff0c;突然萌生了一个想法&#xff1a;能不能让这个充满回忆的硬件&#xff0c;在现代的电脑或开源硬件平台上重新“活…

作者头像 李华
网站建设 2026/8/13 12:29:44

如何用 ComfyUI-Impact-Pack 让你的 AI 图像一步到专业级?

如何用 ComfyUI-Impact-Pack 让你的 AI 图像一步到专业级&#xff1f; 【免费下载链接】ComfyUI-Impact-Pack Custom nodes pack for ComfyUI This custom node helps to conveniently enhance images through Detector, Detailer, Upscaler, Pipe, and more. 项目地址: http…

作者头像 李华