1. 网页抓取基础入门

第一次接触网页抓取时,我也被各种专业术语搞得晕头转向。其实说白了,网页抓取就是让程序自动去访问网页,然后把我们需要的内容"抄"下来。就像你用浏览器打开网页后按Ctrl+S保存网页一样,只不过现在是让代码帮你完成这个操作。

在Python中,最常用的网页抓取库是urllib和requests。这里以urllib为例,先来看个最简单的例子:

import urllib.request

url = 'http://example.com'
response = urllib.request.urlopen(url)
html_content = response.read().decode('utf-8')
print(html_content[:500])  # 打印前500个字符

这段代码做了三件事:

  1. 用urlopen打开网页链接
  2. 用read()方法读取网页内容
  3. 用decode('utf-8')将字节数据转为字符串

新手常会遇到的一个坑是忘记解码。网页返回的数据默认是bytes类型,直接操作会报错。记得一定要用decode()转为字符串,通常用utf-8编码就能搞定大多数情况。

2. 实战:Educoder作业解析

2.1 数据获取阶段

在Educoder的作业中,第一步要求我们从指定URL获取网页内容。关键代码其实就四行:

webpage = req.urlopen(url)
webdata = webpage.read()
webdata = webdata.decode('utf-8')
outfile.write(webdata)

我建议新手可以先用浏览器打开目标网页,右键"查看页面源代码",确认下网页结构。有时候网页用了JavaScript动态加载,这种简单方法就抓不到内容了,需要更高级的工具如Selenium。

2.2 链接提取技巧

作业的第二部分要求提取历年分数线的链接。原始代码用了字符串查找的笨办法:

for i in range(2012, 2017):
    mdl = Gfkd + str(i)
    idx = webdata.find(mdl)
    while webdata[idx : idx + 4] != 'href':
        idx -= 1
    urls.append(pre + webdata[idx + 7 : idx + 47])

这种方法虽然能用,但非常脆弱。一旦网页结构稍有变化就会失效。更稳妥的做法是用BeautifulSoup:

from bs4 import BeautifulSoup
soup = BeautifulSoup(webdata, 'html.parser')
links = [a['href'] for a in soup.find_all('a') if '录取分数' in a.text]

3. 正则表达式实战应用

3.1 基础正则语法

正则表达式是处理文本的瑞士军刀。作业中用到的几个关键模式:

  • r'<table.*?>(.*?)</table>':匹配table标签及内容
  • r'<tr.*?>(.*?)</tr>':匹配tr行标签
  • r'<td.*?>(.*?)</td>':匹配td单元格

这里的.*?是非贪婪匹配,会匹配尽可能少的内容。re.S标志让.也能匹配换行符。

3.2 数据清洗实战

从HTML表格提取数据后,通常需要清洗:

mdl = mdl.strip()  # 去首尾空格
mdl = mdl.replace(' ', '')  # 去普通空格
mdl = mdl.replace(' ', '')  # 去全角空格
mdl = mdl.replace('&nbsp;', '')  # 去HTML空格实体

实际项目中,数据清洗可能占整个流程70%的工作量。除了空格,还要处理乱码、特殊符号、异常值等。建议准备一个清洗函数库,把常用操作封装起来。

4. 完整爬虫架构设计

一个健壮的爬虫应该包含以下模块:

  1. 下载器:负责发送请求获取网页

    • 需要处理重试机制
    • 设置合理的User-Agent
    • 控制请求频率
  2. 解析器:提取目标数据

    • 支持多种解析方式(XPath/CSS选择器/正则)
    • 处理解析异常
    • 数据初步清洗
  3. 存储器:保存结果

    • 支持多种存储格式(文本/CSV/数据库)
    • 处理编码问题
    • 实现增量存储
  4. 监控模块:日志和报警

    • 记录运行状态
    • 异常报警
    • 性能监控
class SimpleCrawler:
    def __init__(self):
        self.downloader = Downloader()
        self.parser = Parser()
        self.storage = Storage()
    
    def crawl(self, url):
        html = self.downloader.fetch(url)
        data = self.parser.parse(html)
        self.storage.save(data)

5. 常见问题与解决方案

5.1 反爬虫应对策略

很多网站会有反爬措施,常见问题和解决方法:

  1. 请求频率过高被封

    • 解决方案:在每个请求间加随机延迟
    import time
    import random
    time.sleep(random.uniform(0.5, 1.5))
    
  2. 需要登录才能访问

    • 解决方案:使用session保持登录状态
    session = requests.Session()
    session.post(login_url, data=credentials)
    
  3. 验证码拦截

    • 解决方案:使用打码平台或机器学习识别

5.2 性能优化技巧

当需要抓取大量页面时,可以考虑:

  1. 多线程/协程:使用concurrent.futures或asyncio

    from concurrent.futures import ThreadPoolExecutor
    
    with ThreadPoolExecutor(max_workers=5) as executor:
        executor.map(download_page, url_list)
    
  2. 缓存机制:避免重复下载

    import hashlib
    from os.path import exists
    
    def get_cache_key(url):
        return hashlib.md5(url.encode()).hexdigest()
    
    if exists(get_cache_key(url)):
        return read_from_cache(url)
    
  3. 增量抓取:只抓取更新的内容

    • 记录最后更新时间
    • 使用ETag/Last-Modified头

6. 数据存储与后续处理

6.1 存储格式选择

根据数据量和使用场景:

  1. 小型项目:CSV或JSON文件

    import csv
    with open('data.csv', 'w') as f:
        writer = csv.writer(f)
        writer.writerows(data)
    
  2. 中型项目:SQLite或MySQL

    import sqlite3
    conn = sqlite3.connect('data.db')
    c = conn.cursor()
    c.execute('CREATE TABLE IF NOT EXISTS scores (year INT, province TEXT, score INT)')
    
  3. 大型项目:MongoDB或Elasticsearch

6.2 数据分析入门

存储完数据后,可以用pandas做简单分析:

import pandas as pd
df = pd.read_csv('data.csv')
print(df.describe())  # 描述性统计
print(df.groupby('year').mean())  # 按年份分组求均值

对于网页抓取的数据,常见的分析包括:

  • 时间趋势分析
  • 地域分布分析
  • 文本关键词提取

7. 项目实战建议

最后给初学者几个实用建议:

  1. 从小项目开始:先尝试抓取单个页面,再扩展
  2. 遵守robots.txt:尊重网站的抓取规则
  3. 异常处理要完善:网络请求可能失败,解析可能出错
  4. 代码要模块化:把下载、解析、存储分开
  5. 做好日志记录:方便排查问题

一个完整的爬虫项目应该像这样组织目录:

project/
├── crawler/      # 爬虫核心代码
├── config/       # 配置文件
├── data/         # 原始数据
├── processed/    # 处理后的数据
├── utils/        # 工具函数
└── main.py       # 入口文件
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐