网络爬虫简介与基本原理
网络爬虫(Web Crawler)是一种自动化程序,能够按照预定规则浏览互联网并抓取所需数据。它模拟人类浏览网页的行为,通过HTTP请求获取网页内容,然后解析并提取有价值的信息。网络爬虫广泛应用于搜索引擎、数据分析、价格监控和市场研究等领域。
网络爬虫的工作流程通常包括以下几个步骤:
- 发送HTTP请求获取网页内容
- 解析HTML文档结构
- 提取目标数据
- 存储或处理数据
- 调度和管理爬取任务
在开始编写爬虫前,需要了解一些基本概念:
- HTML:网页的结构语言,爬虫主要解析的对象
- CSS选择器/XPath:用于定位和提取HTML元素的查询语言
- HTTP协议:网络请求的基础协议
- User-Agent:标识客户端身份的请求头字段
Python爬虫开发环境搭建
必要工具安装
首先确保已安装Python 3.6+版本,然后安装以下核心库:
pip install requests beautifulsoup4 lxml selenium scrapy
- requests:发送HTTP请求的库
- beautifulsoup4:HTML/XML解析库
- lxml:高效的解析器
- selenium:浏览器自动化工具,用于处理JavaScript渲染的页面
- scrapy:专业爬虫框架
开发环境配置
推荐使用VS Code或PyCharm作为开发IDE,并安装相关插件:
- Python扩展
- REST Client(测试HTTP请求)
- User-Agent切换插件
基础爬虫实战:静态网页抓取
使用requests获取网页内容
import requests
def fetch_page(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status() # 检查请求是否成功
return response.text
except requests.RequestException as e:
print(f"请求失败: {e}")
return None
# 示例:抓取百度首页
html = fetch_page('https://www.baidu.com')
if html:
print("页面获取成功,长度:", len(html))
使用BeautifulSoup解析HTML
from bs4 import BeautifulSoup
def parse_title(html):
if not html:
return None
soup = BeautifulSoup(html, 'lxml')
# 提取<title>标签内容
title = soup.find('title')
return title.get_text() if title else "无标题"
# 示例解析
if html:
title = parse_title(html)
print(f"网页标题: {title}")
完整示例:抓取豆瓣电影Top250
import requests
from bs4 import BeautifulSoup
import time
def scrape_douban_top250():
base_url = "https://movie.douban.com/top250"
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'
}
movies = []
for start in range(0, 250, 25):
url = f"{base_url}?start={start}"
try:
response = requests.get(url, headers=headers, timeout=10)
soup = BeautifulSoup(response.text, 'lxml')
items = soup.find_all('div', class_='item')
for item in items:
title = item.find('span', class_='title').get_text()
rating = item.find('span', class_='rating_num').get_text()
quote = item.find('span', class_='inq')
quote = quote.get_text() if quote else ""
movies.append({
'title': title,
'rating': rating,
'quote': quote
})
time.sleep(1) # 礼貌性延迟
except Exception as e:
print(f"抓取失败: {e}")
return movies
# 执行抓取并打印前5条结果
if __name__ == "__main__":
movies = scrape_douban_top250()
for i, movie in enumerate(movies[:5]):
print(f"{i+1}. {movie['title']} - 评分: {movie['rating']} - {movie['quote']}")
进阶爬虫:处理动态内容
使用Selenium处理JavaScript渲染页面
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
def setup_driver():
options = Options()
options.add_argument('--headless') # 无头模式
options.add_argument('--disable-gpu')
options.add_argument('--no-sandbox')
options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
driver = webdriver.Chrome(options=options)
return driver
def scrape_dynamic_content(url):
driver = setup_driver()
try:
driver.get(url)
# 等待特定元素加载(最多10秒)
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "div.content"))
)
content = driver.page_source
return content
finally:
driver.quit()
# 示例:抓取需要JavaScript渲染的页面
if __name__ == "__main__":
html = scrape_dynamic_content("https://example.com")
if html:
print("动态页面内容:", html[:200])
使用Scrapy框架构建专业爬虫
# 创建Scrapy项目:scrapy startproject tutorial
# 以下是一个简单的Scrapy爬虫示例
import scrapy
class BlogSpider(scrapy.Spider):
name = 'blogspider'
start_urls = ['https://blog.example.com']
def parse(self, response):
# 提取所有文章标题和链接
for article in response.css('div.article'):
yield {
'title': article.css('h2::text').get(),
'link': article.css('a::attr(href)').get(),
'date': article.css('.date::text').get()
}
# 分页处理
next_page = response.css('a.next-page::attr(href)').get()
if next_page:
yield response.follow(next_page, self.parse)
数据存储与管理
存储为CSV文件
import csv
def save_to_csv(data, filename):
if not data:
return
keys = data[0].keys()
with open(filename, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=keys)
writer.writeheader()
writer.writerows(data)
# 示例
movies = scrape_douban_top250()
save_to_csv(movies, 'douban_top250.csv')
存储到SQLite数据库
import sqlite3
def create_db():
conn = sqlite3.connect('movies.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS movies
(id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
rating REAL,
quote TEXT)''')
conn.commit()
conn.close()
def save_to_db(data):
conn = sqlite3.connect('movies.db')
c = conn.cursor()
for movie in data:
c.execute("INSERT INTO movies (title, rating, quote) VALUES (?, ?, ?)",
(movie['title'], float(movie['rating']), movie['quote']))
conn.commit()
conn.close()
# 使用示例
create_db()
save_to_db(movies)
反爬虫策略与应对方法
常见反爬虫技术
- User-Agent检测:检查请求头是否像浏览器
- IP频率限制:同一IP频繁访问会封禁
- 验证码:需要人工识别
- 动态Token:每次请求需要携带变化的token
- JavaScript混淆:增加解析难度
应对策略
import random
import time
from fake_useragent import UserAgent
def get_random_headers():
ua = UserAgent()
return {
'User-Agent': ua.random,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Accept-Encoding': 'gzip, deflate',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
}
def smart_request(url, max_retries=3):
for attempt in range(max_retries):
try:
headers = get_random_headers()
# 随机延迟
time.sleep(random.uniform(1, 3))
response = requests.get(url, headers=headers, timeout=15)
if response.status_code == 200:
return response.text
except Exception as e:
print(f"尝试 {attempt+1} 失败: {e}")
time.sleep(2 ** attempt) # 指数退避
return None
法律与道德规范
在进行网络爬虫开发时,必须遵守以下原则:
- 遵守robots.txt:检查目标网站的爬虫协议
- 尊重版权:不要抓取受版权保护的内容用于商业用途
- 控制请求频率:避免对目标服务器造成过大负担
- 数据使用规范:不要将抓取的数据用于非法用途
- 隐私保护:不要抓取个人隐私信息
import urllib.robotparser
def can_fetch(url):
rp = urllib.robotparser.RobotFileParser()
rp.set_url(url + "/robots.txt")
try:
rp.read()
return rp.can_fetch("*", url)
except:
return True # 如果无法读取robots.txt,假设允许
# 示例
if can_fetch("https://example.com"):
print("可以抓取该网站")
else:
print("该网站禁止爬虫访问")
总结与最佳实践
网络爬虫是一个强大的工具,但需要负责任地使用。以下是一些最佳实践:
- 先分析后抓取:理解网站结构和数据模式
- 优雅降级:处理异常和错误,不要让爬虫崩溃
- 数据验证:确保抓取的数据准确完整
- 增量抓取:只抓取更新的内容,避免重复工作
- 监控与日志:记录爬虫运行状态和问题
通过本指南,您应该已经掌握了Python爬虫的基础知识和实用技巧。记住,技术是中立的,但使用技术的方式决定了其价值。请始终以合法、道德的方式使用爬虫技术。
