爬虫基本介绍
约 1577 字大约 5 分钟
2025-10-02
爬虫的分类
按爬取规模分类
- 聚焦爬虫
- 针对特定网站或特定内容,有明确的数据采集目标
- 百分之九十的爬虫都是聚焦爬虫
- 通用爬虫
- 什么内容都采集,都存下来,不针对特定网站
- 如搜索引擎的爬虫Googlebot、Baiduspider
- 增量爬虫
- 只爬取更新的内容
- 减少重复爬取和资源消耗
- 既可以是聚焦爬虫,也可以是通用爬虫
- 深网爬虫
- 爬取隐藏在深层链接中的内容
- 需要处理表单提交、登录等复杂交互
按实现方式分类
- 静态页面爬虫
- 基于
HTTP协议的爬虫 - 通过发送
HTTP请求获取网页内容 - 使用
Requests+BeautifulSoup/lxml组合 - 实现简单,速度快
- 基于
import requests
from bs4 import BeautifulSoup
url = 'http://example.com'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
# 提取数据...- 动态页面爬虫
- 基于浏览器的爬虫
- 处理JavaScript渲染的内容
- 模拟用户在浏览器中的操作,速度较慢
- 使用
Selenium、Pyppeteer等工具
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('http://example.com')
# 等待页面加载完成
element = driver.find_element_by_id('content')
# 提取数据...
driver.quit()API接口爬虫- 直接调用网站提供的
API接口获取数据 - 效率高,数据结构规范
- 需要分析
API请求方式 - 如使用
Requests库调用RESTful API
- 直接调用网站提供的
import requests
url = 'http://api.example.com/data'
params = {'key': 'value'}
headers = {'Authorization': 'Bearer token'}
response = requests.get(url, params=params, headers=headers)
data = response.json()
# 提取数据...常用Python爬虫库
Requests: 发送HTTP请求,获取网页内容BeautifulSoup: 解析HTML和XML文档Scrapy: 一个强大的爬虫框架Selenium: 浏览器自动化工具,可用于自动化测试、爬虫PyQuery: 用于解析HTML文档,类似于jQuerylxml: 一个高性能的HTML和XML解析库
爬虫的合法性
基本前提
- 遵守robots协议
- 检查目标网站的
robots.txt文件 - 尊重网站规定的爬取限制
- 禁止爬取的目录应避免访问
- 检查目标网站的
- 合理使用原则:
- 不干扰网站正常运行(拒绝服务攻击)
- 设置合理的请求间隔(通常≥2秒)
- 避免对服务器造成过大负担
- 数据使用限制:
- 仅用于个人学习或合法研究
- 不用于商业牟利(除非获得授权)
- 不侵犯用户隐私和个人信息
可能构成违法的行为
- 绕过技术防护措施:
- 破解验证码系统
- 伪造或盗用身份认证信息
- 使用代理IP池规避IP封锁
- 违反服务条款(TOS):
- 多数网站用户协议明确禁止自动化抓取
- 典型案例:LinkedIn vs hiQ Labs案
- 侵犯特定类型数据:
- 爬取受版权保护内容
- 获取个人隐私数据(GDPR相关)
- 采集商业秘密或国家安全信息
- 不正当竞争行为:
- 恶意抓取竞争对手数据导致目标服务器瘫痪
- 通过爬虫实施价格监控等商业行为
合规建议
- 前期评估
- 检查目标网站的服务条款
- 咨询法律专业人士意见
- 进行数据分类风险评估
- 技术合规措施
# 示例:合规爬虫代码结构
import requests
import time
from urllib.robotparser import RobotFileParser
# 1. 检查robots.txt
rp = RobotFileParser()
rp.set_url("https://example.com/robots.txt")
rp.read()
# 2. 遵守爬取间隔
if rp.can_fetch("*", target_url):
response = requests.get(target_url, headers={
'User-Agent': 'MyLegalBot/1.0 (+http://mywebsite.com/bot-info)'
})
time.sleep(3) # 遵守延迟设置
# 处理数据...
else:
print("Disallowed by robots.txt")- 数据使用规范
- 建立数据使用日志
- 实施数据脱敏处理
- 设置数据保留期限
系统工作流程
目标网站分析
网站结构调研
- 了解导航结构、URL规律
- 检查robots.txt文件,了解爬取规则
- 确定目标数据在HTML中的位置
- 分析列表页翻页逻辑
技术特征检测
- 页面类型判断
# 快速检测是否动态渲染 import requests r = requests.get(url) if len(r.text) < 500 and '<div id="root"></div>' in r.text: print("疑似动态渲染页面,需用Selenium/Puppeteer") - 反爬措施识别
- 检查是否有Cloudflare等WAF防护
- 测试是否需要登录才能访问
- 观察是否有验证码弹出
- 数据接口探查
- 浏览器开发者工具检查XHR请求
- 寻找隐藏的API接口(Network面板过滤XHR/JS)
- 分析接口参数加密方式
- 页面类型判断
法律合规准备
法律风险评估
- 确认数据是否涉及个人隐私(GDPR/个人信息保护法)
- 评估数据使用目的是否合规
- 检查目标网站的服务条款和隐私政策
合规措施准备
- 准备规范的User-Agent标识
headers = { 'User-Agent': 'Mozilla/5.0 (兼容研究项目; +http://你的网站/bot-info)' } - 设计合理的爬取间隔(建议≥3秒)
- 规划数据存储安全方案
- 准备规范的User-Agent标识
技术环境准备
- 基础库安装
pip install requests beautifulsoup4 lxml scrapy selenium pyquery浏览器驱动
- 对于动态页面爬虫,需安装浏览器驱动
- Chrome用户需下载ChromeDriver
- Firefox用户需下载GeckoDriver
代理IP池配置(可选)
import requests from itertools import cycle # 代理IP列表 proxies = [ 'http://user:pass@proxy1.com:port', 'http://user:pass@proxy2.com:port', 'http://user:pass@proxy3.com:port', ] proxy_pool = cycle(proxies) # 使用代理池发送请求 for i in range(1, 6): proxy = next(proxy_pool) try: response = requests.get('http://example.com', proxies={'http': proxy, 'https': proxy}) print(f"Request {i}成功,使用代理:{proxy}") except requests.exceptions.ProxyError: print(f"Request {i}失败,代理:{proxy}不可用")存储方案设计
- 小规模数据:
CSV/JSON文件
import pandas as pd df = pd.DataFrame(data) df.to_csv('data.csv', index=False)- 中大规模数据:
MySQL、MongoDB - 分布式存储:
Redis+Scrapy
- 小规模数据:
效率优化
增量爬取策略
- URL去重设计
- 数据更新识别机制
性能优化
- 采用连接池复用连接,减少连接建立时间
- 使用异步请求库(如
aiohttp)提高并发性能
import aiohttp import asyncio async def fetch_data(session, url): async with session.get(url) as response: return await response.json() async def main(urls): async with aiohttp.ClientSession() as session: tasks = [fetch_data(session, url) for url in urls] return await asyncio.gather(*tasks) urls = ['http://example.com/api/data1', 'http://example.com/api/data2'] data = asyncio.run(main(urls))
