使用 Python 构建复杂爬虫

60 阅读4分钟

以下是使用 Python 构建复杂爬虫的完整技术实现方案,包含登录/注册、文件解析和反爬虫绕过策略。请注意,本示例仅用于教育目的,请遵守目标网站的 robots.txt 和服务条款。

import requests
from bs4 import BeautifulSoup
import os
import time
import random
from fake_useragent import UserAgent
from io import BytesIO
from PIL import Image
import pytesseract
import pdfplumber
from docx import Document
import openpyxl

# ======== 配置部分 ========
BASE_URL = "https://example.com"
PROXY_POOL = ["http://proxy1:port", "http://proxy2:port"]  # 需自行配置代理
SESSION = requests.Session()

# ======== 工具函数 ========
def get_random_headers():
    """生成随机请求头"""
    ua = UserAgent()
    return {
        'User-Agent': ua.random,
        'Accept-Language': 'en-US,en;q=0.9',
        'Referer': BASE_URL
    }

def rotate_proxy():
    """代理轮换"""
    return {'http': random.choice(PROXY_POOL)}

def safe_delay():
    """随机延迟(反爬虫)"""
    time.sleep(random.uniform(1, 3))

# ======== 验证码处理 ========
def handle_captcha(session, captcha_url):
    """处理图像验证码"""
    response = session.get(captcha_url)
    img = Image.open(BytesIO(response.content))
    
    # 预处理增强识别率
    img = img.convert('L')  # 灰度处理
    img = img.point(lambda x: 0 if x < 128 else 255)  # 二值化
    
    captcha = pytesseract.image_to_string(img)
    return captcha.strip()

# ======== 登录模块 ========
def login(username, password):
    login_url = f"{BASE_URL}/login"
    
    # 首次获取登录页面获取CSRF token
    response = SESSION.get(login_url, headers=get_random_headers())
    soup = BeautifulSoup(response.text, 'html.parser')
    csrf_token = soup.find('input', {'name': 'csrf_token'}).get('value')
    
    # 处理验证码
    captcha_url = f"{BASE_URL}/captcha.jpg?t={int(time.time())}"
    captcha_code = handle_captcha(SESSION, captcha_url)
    
    # 构造登录数据
    payload = {
        'username': username,
        'password': password,
        'csrf_token': csrf_token,
        'captcha': captcha_code
    }
    
    # 发送登录请求
    response = SESSION.post(login_url, 
                          data=payload,
                          headers=get_random_headers(),
                          proxies=rotate_proxy())
    
    # 验证登录成功
    if 'Welcome' in response.text:
        print("登录成功")
        return True
    else:
        print("登录失败")
        return False

# ======== 文件下载解析模块 ========
def download_file(file_url):
    """通用文件下载器"""
    response = SESSION.get(file_url, 
                         stream=True,
                         headers=get_random_headers(),
                         proxies=rotate_proxy())
    
    content_type = response.headers.get('Content-Type', '')
    file_content = response.content
    
    # 根据内容类型解析文件
    if 'pdf' in content_type:
        return parse_pdf(file_content)
    elif 'word' in content_type:
        return parse_docx(file_content)
    elif 'excel' in content_type:
        return parse_excel(file_content)
    else:
        return save_raw_file(file_content)

def parse_pdf(content):
    """解析PDF文件"""
    text = []
    with pdfplumber.open(BytesIO(content)) as pdf:
        for page in pdf.pages:
            text.append(page.extract_text())
    return {'type': 'pdf', 'content': '\n'.join(text)}

def parse_docx(content):
    """解析Word文档"""
    doc = Document(BytesIO(content))
    return {'type': 'docx', 'content': '\n'.join([p.text for p in.doc.paragraphs])}

def parse_excel(content):
    """解析Excel文件"""
    wb = openpyxl.load_workbook(BytesIO(content))
    sheet = wb.active
    data = []
    for row in sheet.iter_rows(values_only=True):
        data.append(list(row))
    return {'type': 'excel', 'content': data}

# ======== 反爬虫绕过策略 ========
class AntiAntiCrawler:
    @staticmethod
    def mimic_human_behavior(driver):
        """模拟人类操作模式(用于Selenium)"""
        # 随机鼠标移动
        action = webdriver.ActionChains(driver)
        for _ in range(random.randint(2,5)):
            action.move_by_offset(
                random.randint(-10,10), 
                random.randint(-10,10)
            ).perform()
            time.sleep(0.2)
    
    @staticmethod
    def handle_cloudflare(webdriver):
        """处理Cloudflare验证"""
        time.sleep(5)  # 等待人工干预
        if "challenge" in webdriver.current_url:
            raise Exception("需要人工处理验证码")

# ======== 主爬虫类 ========
class AdvancedCrawler:
    def __init__(self):
        self.session = requests.Session()
        self.cookies = None
    
    def start(self, start_url):
        safe_delay()
        try:
            response = self.session.get(start_url,
                                       headers=get_random_headers(),
                                       proxies=rotate_proxy())
            
            # 检测反爬机制
            if response.status_code == 403:
                self._handle_blocking()
                return self.start(start_url)
            
            # 解析页面内容
            soup = BeautifulSoup(response.text, 'html.parser')
            
            # 提取文件链接
            file_links = self._extract_file_links(soup)
            
            # 下载并处理文件
            for link in file_links:
                file_data = download_file(link)
                self._classify_and_save(file_data)
                
        except Exception as e:
            print(f"爬取失败: {str(e)}")
            self._handle_error()
    
    def _extract_file_links(self, soup):
        # 实现具体的链接提取逻辑
        return [a['href'] for a in soup.find_all('a', href=True) 
                if any(ext in a['href'] for ext in ['.pdf', '.docx', '.xlsx'])]
    
    def _classify_and_save(self, file_data):
        # 实现文件分类存储逻辑
        save_dir = f"downloads/{file_data['type']}"
        os.makedirs(save_dir, exist_ok=True)
        filename = f"{int(time.time())}_{random.randint(1000,9999)}"
        
        with open(f"{save_dir}/{filename}", 'w') as f:
            f.write(str(file_data['content']))
    
    def _handle_blocking(self):
        # 反反爬虫处理策略
        print("检测到封禁,执行应对措施...")
        time.sleep(60)  # 冷却时间
        SESSION.proxies.update(rotate_proxy())
        SESSION.headers.update(get_random_headers())

# ======== 使用示例 ========
if __name__ == "__main__":
    # 初始化爬虫
    crawler = AdvancedCrawler()
    
    # 执行登录
    if login("your_username", "your_password"):
        # 开始爬取
        crawler.start(f"{BASE_URL}/target_page")
    else:
        print("无法继续:登录失败")

关键技术和绕过策略说明

  1. 身份验证增强

    • 自动CSRF令牌处理
    • Tesseract OCR验证码识别
    • 会话保持和Cookie管理
  2. 反爬虫对抗

    • 随机请求头(使用fake_useragent)
    • 代理池轮换(需自行配置可靠代理)
    • 人类操作模式模拟(延迟、鼠标移动)
    • 自动重试和封禁处理机制
  3. 文件处理增强

    • 支持PDF、Word、Excel等多种格式
    • 自动内容类型检测
    • 结构化数据提取
  4. 稳定性增强

    • 异常处理机制
    • 自动冷却系统
    • 请求重试逻辑

必要依赖安装

pip install requests beautifulsoup4 fake-useragent pytesseract pdfplumber python-docx openpyxl pillow

注意事项

  1. 需自行配置代理服务器(推荐使用付费代理服务)
  2. 验证码识别准确率可能不足,建议:
    • 使用商业OCR服务(如AWS Textract)
    • 人工验证码处理接口
  3. 遵守目标网站的robots.txt和法律法规
  4. 根据具体网站结构调整选择器和解析逻辑
  5. 对于复杂JavaScript渲染页面,需配合Selenium/Puppeteer使用

请根据实际需求调整代码,并确保您的爬虫行为符合当地法律法规和网站的服务条款。