一、爬虫技术概述与基础实现
网络爬虫是一种自动化程序,能够模拟人类浏览网页的行为,从互联网上抓取所需的数据。在当今大数据时代,爬虫技术已成为数据采集的重要手段,广泛应用于搜索引擎、数据分析、市场研究等领域。
基础爬虫实现原理
一个最简单的爬虫通常包含以下三个步骤:
-
发送HTTP请求:向目标网站服务器发送请求,获取网页内容
-
解析响应内容:从返回的HTML中提取结构化数据
-
存储结果:将提取的数据保存到文件或数据库
下面是一个使用Python标准库实现的基础爬虫示例:
import requests
from bs4 import BeautifulSoup
def get_webpage_title(url):
"""获取网页标题的基础爬虫函数"""
try:
# 设置请求头,模拟浏览器访问
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
}
# 发送HTTP GET请求
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status() # 检查请求是否成功
# 使用BeautifulSoup解析HTML
soup = BeautifulSoup(response.text, 'html.parser')
# 提取网页标题
title = soup.title.string if soup.title else '无标题'
return title.strip()
except requests.exceptions.RequestException as e:
print(f"请求出错: {e}")
return None
# 使用示例
if __name__ == '__main__':
test_url = 'https://www.baidu.com'
page_title = get_webpage_title(test_url)
print(f"网页标题: {page_title}")
二、爬虫进阶技术与实战案例
1. 处理分页内容的爬虫
实际项目中,我们经常需要抓取分页数据。以下示例展示如何抓取多页内容:
import requests
from bs4 import BeautifulSoup
import time
def crawl_paginated_data(base_url, max_pages=5):
"""抓取分页数据的爬虫"""
all_data = []
for page in range(1, max_pages + 1):
try:
# 构造分页URL
url = f"{base_url}?page={page}"
print(f"正在抓取: {url}")
response = requests.get(url, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
# 假设每页有多个.item元素包含我们需要的数据
items = soup.select('.item')
for item in items:
data = {
'title': item.select_one('.title').text.strip(),
'price': item.select_one('.price').text.strip(),
'date': item.select_one('.date').text.strip()
}
all_data.append(data)
# 礼貌性延迟,避免给服务器造成压力
time.sleep(1)
except Exception as e:
print(f"第{page}页抓取失败: {e}")
continue
return all_data
关键点说明:
分页URL构造技巧
使用CSS选择器精准定位元素
添加适当的请求间隔(time.sleep)
完善的异常处理机制
2. 处理动态内容的爬虫(Selenium方案)
现代网站大量使用JavaScript动态加载内容,传统爬虫难以应对。这时可以使用Selenium等工具:
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 crawl_dynamic_content(url):
"""抓取动态加载内容的爬虫"""
# 配置浏览器选项
chrome_options = Options()
chrome_options.add_argument('--headless') # 无界面模式
chrome_options.add_argument('--disable-gpu')
driver = webdriver.Chrome(options=chrome_options)
results = []
try:
driver.get(url)
# 等待主要内容加载完成
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, 'main-content'))
# 模拟滚动加载更多内容
last_height = driver.execute_script("return document.body.scrollHeight")
while True:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2) # 等待新内容加载
new_height = driver.execute_script("return document.body.scrollHeight")
if new_height == last_height:
break
last_height = new_height
# 提取动态加载的内容
items = driver.find_elements(By.CSS_SELECTOR, '.dynamic-item')
for item in items:
data = {
'name': item.find_element(By.CSS_SELECTOR, '.name').text,
'value': item.find_element(By.CSS_SELECTOR, '.value').text
}
results.append(data)
finally:
driver.quit()
return results
技术要点:
无头浏览器配置
显式等待(WebDriverWait)确保元素加载
模拟滚动操作触发动态加载
资源释放(driver.quit())避免内存泄漏
三、爬虫工程化实践
1. 使用Scrapy框架构建爬虫项目
Scrapy是Python最强大的爬虫框架之一,适合构建生产级爬虫:
import scrapy
from scrapy.crawler import CrawlerProcess
class NewsSpider(scrapy.Spider):
name = 'news_spider'
start_urls = ['https://news.example.com/latest']
custom_settings = {
'DOWNLOAD_DELAY': 2, # 下载延迟
'CONCURRENT_REQUESTS': 4, # 并发请求数
'FEED_FORMAT': 'json',
'FEED_URI': 'news_output.json'
}
def parse(self, response):
# 提取新闻条目
for article in response.css('article.news-item'):
yield {
'title': article.css('h2.title::text').get().strip(),
'summary': article.css('p.summary::text').get().strip(),
'publish_date': article.css('time::attr(datetime)').get(),
'link': response.urljoin(article.css('a.read-more::attr(href)').get())
}
# 跟踪分页链接
next_page = response.css('a.next-page::attr(href)').get()
if next_page:
yield response.follow(next_page, self.parse)
# 运行爬虫
if __name__ == '__main__':
process = CrawlerProcess()
process.crawl(NewsSpider)
process.start()
框架优势:
内置的异步处理机制
完善的中间件系统
自动的请求去重
多种数据导出格式支持
2. 反爬策略应对方案
现代网站通常会有各种反爬机制,我们需要相应策略:
import random
import requests
from fake_useragent import UserAgent
class AntiAntiSpider:
def __init__(self):
self.ua = UserAgent()
self.proxy_pool = [
'http://proxy1.example.com:8080',
'http://proxy2.example.com:8080'
]
def get_with_protection(self, url):
try:
headers = {
'User-Agent': self.ua.random,
'Accept-Language': 'en-US,en;q=0.9',
'Referer': 'https://www.google.com/'
}
proxy = {'http': random.choice(self.proxy_pool)}
response = requests.get(
url,
headers=headers,
proxies=proxy,
timeout=15,
cookies={'session_token': 'random_value'}
)
# 检查是否被拦截
if 'access denied' in response.text.lower():
raise Exception('访问被拒绝')
return response.text
except Exception as e:
print(f"请求失败: {e}")
return None
反反爬技术:
随机User-Agent
代理IP池
请求头模拟
请求间隔随机化
Cookie处理
四,代码示例
以下是我写的代码
以下是对这段Python代码的详细介绍,包含功能说明、代码结构解析、技术点分析及注意事项:
一、代码功能概述
这段代码是一个网络爬虫程序,用于从上海软科中国大学排名官网( https://www.shanghairanking.cn )获取2021-2023年的中国大学排名数据,并将数据整理后保存为CSV文件。具体实现了以下功能:
1. 模拟浏览器请求:通过设置请求头伪装成Chrome浏览器,避免被网站识别为爬虫。
2. 网页数据解析:使用BeautifulSoup解析HTML页面,提取表格中的大学排名信息。
3. 数据持久化:将爬取的数据保存到CSV文件,方便后续分析。
4. 反反爬虫策略:通过随机延时控制请求频率,降低对目标网站的压力。
二、代码结构与关键细节
1. 导入依赖库
import requests
from bs4 import BeautifulSoup
import csv
import time
import random
- requests :发送HTTP请求,获取网页内容。
- BeautifulSoup :解析HTML文档,提取目标数据。
- csv :处理CSV文件的读写操作。
- time & random :控制请求间隔,模拟真实用户行为。
2. 请求头设置
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'}
- 作用:伪装成Chrome浏览器,避免被网站通过 User-Agent 字段识别为爬虫程序。
- 原理:HTTP请求头中的 User-Agent 字段用于标识客户端类型,网站可通过该字段过滤可疑请求。
3. 获取排名数据函数 get_ranking_data(year)
def get_ranking_data(year):
url = f'https://www.shanghairanking.cn/rankings/bcur/{year}' # 构造URL
try:
response = requests.get(url, headers=headers)
response.raise_for_status() # 检查请求是否成功(状态码非200时抛出异常)
response.encoding = 'utf-8' # 设置响应编码,避免中文乱码
soup = BeautifulSoup(response.text, 'html.parser') # 解析HTML
ranking_table = soup.find('table', {'class': 'rk-table'}) # 查找排名表格
if not ranking_table: # 处理表格不存在的情况
print(f"未找到{year}年的排名表格")
return []
rows = ranking_table.find_all('tr')[1:] # 跳过表头行,提取数据行
ranking_data = []
for row in rows:
cols = row.find_all('td') # 提取每行的所有单元格
if len(cols) >= 4: # 确保该行有足够的列数据
rank = cols[0].text.strip() # 排名
# 处理学校名称(可能包含链接或纯文本)
name = cols[1].find('a').text.strip() if cols[1].find('a') else cols[1].text.strip()
province = cols[2].text.strip() # 省份
score = cols[3].text.strip() # 总分
ranking_data.append({...}) # 保存为字典格式
return ranking_data
except Exception as e: # 统一异常处理
print(f"获取{year}年排名数据时出错:", e)
return []
- URL构造:通过 f-string 生成不同年份的URL(如 https://www.shanghairanking.cn/rankings/bcur/2021 )。
- 异常处理:使用 response.raise_for_status() 检查请求状态,捕获网络错误或页面不存在等异常。
- HTML解析:
- BeautifulSoup 将HTML文本转换为可操作的树形结构。
- 通过 find() 和 find_all() 方法定位表格( class="rk-table" )及行( tr )、列( td )元素。
- 跳过表头行( [1:] ),仅处理数据行。
- 数据清洗:使用 strip() 去除文本首尾空格,处理学校名称可能存在的超链接( a 标签)。
4. 保存数据到CSV函数 save_to_csv(data, filename)
def save_to_csv(data, filename):
if not data: # 处理无数据情况
print("无数据可保存")
return
try:
with open(filename, mode='w', encoding='utf-8-sig', newline='') as file:
writer = csv.DictWriter(file, fieldnames=data[0].keys()) # 根据字典键生成CSV表头
writer.writeheader() # 写入表头
writer.writerows(data) # 写入数据行
print(f"数据已成功保存到{filename}")
except Exception as e:
print("保存文件时出错:", e)
- 编码处理:使用 utf-8-sig 编码,确保CSV文件在Excel中打开时不出现中文乱码( sig 表示添加BOM头)。
- csv.DictWriter :直接根据字典列表写入CSV,字段名由字典键自动生成,代码简洁易维护。
5. 主函数 main()
def main():
years = [2021, 2022, 2023] # 目标年份列表
all_data = []
for year in years:
data = get_ranking_data(year)
all_data.extend(data)
time.sleep(random.uniform(1, 3)) # 随机延时1-3秒
save_to_csv(all_data, '中国大学排名.csv') # 合并数据后保存
- 循环爬取:依次获取三年数据,合并到 all_data 列表中。
- 随机延时: time.sleep(random.uniform(1, 3)) 模拟真实用户浏览间隔,避免短时间内高频请求导致IP封禁。
三、技术点与反反爬虫策略
1. 模拟浏览器请求:
- 通过 User-Agent 伪装浏览器,可进一步添加 Referer 、 Accept 等请求头字段增强伪装效果。
2. 控制请求频率:
- 随机延时(而非固定间隔)更接近真实用户行为,降低被反爬虫机制检测的概率。
3. 异常处理与鲁棒性:
- 包含请求失败、页面结构变化(如表格不存在)、数据格式异常等处理逻辑,提升代码稳定性。
4. 合规性提醒:
- 爬取前需阅读目标网站的 robots.txt 协议,确保操作合法合规。
- 此代码仅用于获取公开可访问的数据,禁止用于侵犯隐私或商业用途。
四、运行结果与文件示例
运行代码后,会在当前目录生成 中国大学排名.csv 文件,内容示例:
年份 排名 学校名称 省份 总分
2021 1 清华大学 北京 99.0
2021 2 北京大学 北京 98.2
... ... ... ... ...
五、扩展与优化建议
1. 并发请求:使用 concurrent.futures 或 aiohttp 实现多线程/异步爬取,提升效率(需注意控制并发量)。
2. 代理IP池:添加代理IP轮换机制,避免单IP被封禁(适用于大规模爬取)。
3. 数据校验:增加数据格式校验(如排名是否为数字、分数是否合法),确保数据质量。
4. 断点续爬:记录已爬取的年份,避免重复请求(可通过日志或数据库实现)。
链接:【金山文档 | WPS云文档】 中国大学排名
https://kdocs.cn/l/cpnc9TYOh9Cj
五,结语
爬虫技术是一个兼具广度和深度的领域,从简单的数据采集到复杂的分布式系统,每个阶段都有值得深入探索的内容。在实际开发中,我们不仅要掌握技术实现,更要注重工程规范和伦理法律问题。希望本文提供的代码示例和技术总结能为你的爬虫学习之旅提供有价值的参考。