Python爬虫入门到实战:3小时学会网页数据采集
在这个数据驱动的时代,手动复制粘贴网页信息早已跟不上节奏。无论是分析竞品价格、监控新闻动态,还是建立个人资料库,掌握Python爬虫技术都是效率倍增的关键。本文将从零开始,带领你逐步搭建一个可复用的爬虫框架,并处理常见的反爬策略。
为什么选择Python作为爬虫工具?Python拥有简洁语法、活跃社区和强大库生态。其中requests库负责网络请求,BeautifulSoup和lxml负责HTML解析,搭配pandas进行数据清洗,几乎可以应对90%的静态网页抓取需求。更重要的是,Python的异常处理机制能让你在抓取失败时优雅降级,而不至于整个程序崩溃。
第一步:环境准备与基础请求
首先,在终端安装必要的第三方库。建议使用虚拟环境,避免依赖冲突:
pip install requests beautifulsoup4 lxml pandas
创建一个新的py文件,我们来发起第一次请求。以抓取一个示例新闻网站为例:
import requests
from bs4 import BeautifulSoup
url = 'https://example-news.com/tech'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'}
response = requests.get(url, headers=headers, timeout=10)
print(response.status_code) # 200表示成功
这里核心是设置User-Agent,伪装成浏览器。多数网站会拒绝没有UA头或明显是脚本的请求,这一步是避免被反爬的基础。
第二步:解析HTML结构——定位目标数据
拿到响应内容后,使用BeautifulSoup进行解析。假设目标页面中,新闻标题都在<h2 class="article-title">标签内:
soup = BeautifulSoup(response.text, 'lxml')
titles = soup.select('h2.article-title a')
for idx, title in enumerate(titles[:5]):
print(idx+1, title.get_text(strip=True), title['href'])
利用CSS选择器可以精准锁定元素。如果你不确定页面结构,可以用浏览器开发者工具(F12)先检查元素,再对应编写选择器。这是整个爬虫开发中最耗时的部分,但一旦找准规律,代码便稳如磐石。
第三步:处理分页与动态加载
大多数列表页都有分页。常见URL模式为/page/2,可以直接循环构造URL。但对于触底加载或点击展开的动态内容,需要分析接口。打开开发者工具的Network面板,找到XHR请求,通常返回JSON数据。
# 模拟POST请求获取下一页数据
api_url = 'https://example-news.com/api/articles?page=2'
json_data = requests.post(api_url, json={'page': 2, 'type': 'tech'}, headers=headers).json()
for item in json_data['data']:
print(item['title'])
理解接口比解析笨重的HTML更高效,且不易被规则变化干扰。
第四步:数据清洗与结构化存储
抓取到的文本往往包含多余空格、换行或广告字符。利用pandas和正则表达式进行清洗:
import pandas as pd
import re
clean_titles = [re.sub(r'\s+', ' ', t).strip() for t in raw_titles]
df = pd.DataFrame({'标题': clean_titles, '链接': links})
df.to_csv('tech_news.csv', index=False, encoding='utf-8-sig')
存储为CSV是通用做法。如果数据量大,可以改用SQLite或MySQL。建议在抓取时保留原始HTML字段,方便后续调试。
第五步:应对反爬策略——限速与代理
许多网站设有IP访问频率限制。最简单的方案是添加time.sleep()随机延迟,模拟人工浏览。更稳妥的是使用代理池,定期更换IP。
import time
import random
proxy_list = ['1.2.3.4:8080', '5.6.7.8:3128']
for page in range(1, 6):
proxy = random.choice(proxy_list)
proxies = {'http': f'http://{proxy}', 'https': f'http://{proxy}'}
try:
resp = requests.get(f'https://example.com/page/{page}', proxies=proxies, timeout=5)
# 解析逻辑...
except requests.exceptions.ProxyError:
print(f'代理 {proxy} 失败,跳过')
time.sleep(random.uniform(1, 3)) # 随机等待1-3秒
如果遇到验证码或登录墙,则需要更高级的Selenium模拟浏览器,但这不在本次基础范围内。记住,爬虫的核心是守规矩——遵守robots.txt文件,控制抓取频率,不要给目标服务器造成压力。
第六步:异常处理与断点续爬
网络不稳定或页面结构变化都可能导致程序中断。建议写一个try/except包裹核心逻辑,并将已经成功抓取的URL记录下来:
finished_file = 'scraped_urls.txt'
scraped_set = set()
if os.path.exists(finished_file):
with open(finished_file) as f:
scraped_set = set(f.read().splitlines())
# 在循环中:
if url in scraped_set:
continue
try:
parse_function(url)
except Exception as e:
log_error(f'异常URL: {url}, 错误: {e}')
else:
with open(finished_file, 'a') as f:
f.write(url + '\n')
这样即使半夜断网,你也能从上次进度继续,而不需要从头开始。
实战案例:抓取今日热榜标题
假设某个本地资讯站有热榜列表,我们将其整合成完整脚本。注意检查页面是否允许爬取。
def fetch_hot_list(base_url):
all_data = []
for page in range(1, 4):
req_url = base_url + f'?page={page}'
try:
r = requests.get(req_url, headers=headers, timeout=5)
r.raise_for_status()
except Exception as e:
print(f'第{page}页失败: {e}')
continue
soup = BeautifulSoup(r.text, 'lxml')
items = soup.select('.hot-item')
for item in items:
title = item.find('a').get_text(strip=True)
score = item.select_one('.score').get_text(strip=True)
all_data.append({'标题': title, '热度': score})
time.sleep(0.5)
return all_data
if __name__ == '__main__':
result = fetch_hot_list('https://example-hub.com/rank')
df = pd.DataFrame(result)
df.to_excel('hot_list.xlsx', index=False)
进阶提醒:爬虫技术本身并无黑灰产属性,关键在于用途是否合规。建议在爬取前查看目标网站的服务条款,并设置合理的请求间隔。对于需要登录才能访问的内容,未经授权请不要强行绕过。
通过以上六个步骤,你已能构建一个稳健的静态网页采集器。当遇到JavaScript渲染的SPA应用,可以学习Playwright或Selenium实现动态渲染页面抓取。技术之路无止境,但方法论是相通的——明确目标、精细解析、稳健存储、优雅容错。现在不妨拿一个小型网站练手,从今天开始你的数据采集之旅吧。
