Python爬虫入门:HTTP请求与网页抓取实战指南
2026/9/12 15:49:16 网站建设 项目流程

1. 爬虫基础:HTTP请求与网页抓取入门

当我们需要从互联网获取数据时,爬虫技术是最直接有效的手段之一。作为从业十余年的数据工程师,我处理过各种规模的爬虫项目,从简单的单页抓取到分布式爬虫系统。今天就从最基础的HTTP请求开始,分享如何正确编写爬虫的基本请求模块。

HTTP请求是爬虫与网站服务器对话的基础语言。就像去餐厅点餐,你需要用服务员能听懂的方式表达需求(GET/POST请求),然后等待厨房(服务器)准备菜品(返回响应)。一个完整的爬虫请求流程包括:建立连接→发送请求→接收响应→解析内容。这看似简单,但实际开发中会遇到各种"意外情况"——反爬机制、网络波动、页面结构变化等。

提示:在开始编写爬虫前,务必检查目标网站的robots.txt文件(如https://www.example.com/robots.txt),了解网站允许抓取的范围和频率限制。这是爬虫开发者的基本职业操守。

2. 核心工具选型:主流爬虫框架对比

2.1 Python生态中的爬虫框架

目前主流的Python爬虫框架主要有以下几种:

  1. Scrapy:工业级框架,适合中大型项目

    • 优势:异步处理、中间件扩展、内置选择器
    • 缺点:学习曲线较陡,对小项目略显笨重
  2. Requests + BeautifulSoup:轻量级组合

    • 优势:简单易用,适合快速开发
    • 缺点:缺乏自动化调度能力
  3. Playwright/Selenium:浏览器自动化工具

    • 优势:能处理JavaScript渲染的页面
    • 缺点:资源消耗大,速度较慢

对于初学者,我建议从Requests库入手。它提供了人性化的API,比如一个基本的GET请求只需要:

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

2.2 框架选择的核心考量因素

选择框架时需要评估:

  • 项目规模(小规模抓取还是持续采集)
  • 目标网站技术栈(静态HTML还是动态渲染)
  • 反爬强度(是否需要模拟浏览器行为)
  • 团队熟悉度(优先选择团队熟悉的技术)

在我的实战经验中,约70%的常规爬取任务用Requests+BeautifulSoup就能解决,20%需要Scrapy这样的专业框架,剩下10%复杂场景才需要动用浏览器自动化工具。

3. HTTP请求实战详解

3.1 请求头(Headers)的精心配置

请求头是爬虫与服务器"沟通礼仪"的关键。常见的必要头信息包括:

headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Referer': 'https://www.google.com/', 'Accept-Encoding': 'gzip, deflate' }

注意:User-Agent不要直接使用python-requests库的默认值,这等于告诉网站你是个爬虫。建议模拟主流浏览器的UA字符串。

3.2 请求参数与超时设置

GET请求传参有两种方式:

  1. URL直接拼接参数:
    url = 'https://api.example.com/search?q=python&page=1'
  2. 使用params参数:
    params = {'q': 'python', 'page': 1} response = requests.get(url, params=params)

POST请求通常需要设置请求体:

data = {'username': 'admin', 'password': '123456'} response = requests.post(url, data=data)

务必设置合理的超时时间(连接超时和读取超时):

# 连接超时3秒,读取超时10秒 response = requests.get(url, timeout=(3, 10))

3.3 响应处理与状态码解析

HTTP状态码是服务器给出的"应答信号",常见的有:

  • 200:请求成功
  • 301/302:重定向
  • 403:禁止访问(可能触发了反爬)
  • 404:页面不存在
  • 500:服务器内部错误

完整的响应处理流程应该包括:

try: response = requests.get(url, headers=headers, timeout=10) response.raise_for_status() # 自动检查4xx/5xx错误 if response.status_code == 200: content = response.content.decode('utf-8') # 进一步处理内容... except requests.exceptions.RequestException as e: print(f"请求失败: {e}")

4. 反爬应对策略与伦理规范

4.1 常见反爬机制及应对方案

  1. User-Agent检测:随机轮换UA字符串
  2. 请求频率限制:添加延迟(time.sleep)
  3. IP封禁:使用代理IP池
  4. 验证码:OCR识别或人工打码
  5. 行为分析:模拟人类操作间隔

建议的请求间隔设置:

import random import time # 随机延迟1-3秒 time.sleep(random.uniform(1, 3))

4.2 爬虫开发者的伦理守则

  1. 遵守robots.txt协议
  2. 控制请求频率(单IP每秒不超过1-2次)
  3. 不抓取敏感/隐私数据
  4. 设置明显的User-Agent标识
  5. 尊重网站的服务条款

我曾经参与的一个电商项目,因为未控制好爬取频率,导致对方服务器负载激增,最终被永久封禁IP段。这个教训让我深刻认识到:爬虫不仅要考虑技术实现,更要考虑对目标网站的影响。

5. 实战案例:抓取新闻网站数据

5.1 目标分析

以抓取某新闻网站头条为例,我们需要:

  1. 分析页面结构(使用浏览器开发者工具)
  2. 确定数据定位方式(CSS选择器/XPath)
  3. 设计异常处理机制

5.2 完整代码实现

import requests from bs4 import BeautifulSoup import time import random def fetch_news(url): headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)', 'Accept': 'text/html,application/xhtml+xml' } try: # 随机延迟 time.sleep(random.uniform(1, 2)) response = requests.get(url, headers=headers, timeout=10) response.raise_for_status() soup = BeautifulSoup(response.text, 'html.parser') news_list = [] # 假设新闻条目有class="news-item" for item in soup.select('.news-item'): title = item.select_one('h2').text.strip() link = item.find('a')['href'] news_list.append({'title': title, 'url': link}) return news_list except Exception as e: print(f"抓取失败: {e}") return [] # 使用示例 news = fetch_news('https://news.example.com/latest') for item in news: print(item['title'], item['url'])

5.3 常见问题排查

  1. 返回空数据:检查选择器是否匹配当前页面结构
  2. 403禁止访问:尝试更新请求头或使用代理
  3. 连接超时:检查网络或增加超时时间
  4. 编码错误:明确指定响应编码(如response.encoding='utf-8')

6. 进阶技巧与性能优化

6.1 会话(Session)保持

对于需要登录或保持状态的网站,使用Session对象:

session = requests.Session() # 登录 login_data = {'user': 'name', 'pass': 'word'} session.post(login_url, data=login_data) # 后续请求会自动保持cookies profile = session.get(profile_url)

6.2 异步请求加速

对于IO密集型任务,可以使用aiohttp实现异步:

import aiohttp import asyncio async def fetch(url): async with aiohttp.ClientSession() as session: async with session.get(url) as response: return await response.text() # 批量抓取 urls = ['url1', 'url2', 'url3'] tasks = [fetch(url) for url in urls] results = await asyncio.gather(*tasks)

6.3 代理IP的使用

当遇到IP限制时,可以通过代理发送请求:

proxies = { 'http': 'http://proxy_ip:port', 'https': 'http://proxy_ip:port' } response = requests.get(url, proxies=proxies)

7. 数据存储与后续处理

7.1 常见存储方案

  1. 文件存储

    import json with open('data.json', 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False)
  2. 数据库存储

    import sqlite3 conn = sqlite3.connect('data.db') cursor = conn.cursor() cursor.execute('INSERT INTO news VALUES (?, ?)', (title, url)) conn.commit()

7.2 数据清洗建议

原始网页数据通常需要:

  1. 去除空白字符(strip())
  2. 处理特殊编码(HTML实体解码)
  3. 验证URL有效性
  4. 去重处理
from html import unescape clean_text = unescape(raw_text).strip()

在长期爬虫项目中,我建议采用"采集→清洗→存储"的分阶段架构,每个环节独立处理,这样当某个环节需要调整时不会影响整体流程。

编写生产级爬虫时,一定要加入完善的日志记录:

import logging logging.basicConfig( filename='spider.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) try: # 爬取代码... logging.info(f"成功抓取 {url}") except Exception as e: logging.error(f"抓取失败 {url}: {str(e)}")

最后提醒一点:随着网站前端技术发展,越来越多的内容通过JavaScript动态加载。对于这类网站,单纯的Requests可能无法获取完整内容,此时需要考虑使用Selenium或Playwright等浏览器自动化工具。但这也意味着更高的资源消耗和更复杂的维护成本,所以技术选型需要根据实际需求权衡。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询