使用Python实现一个简单的Web爬虫(网络爬虫)系统
在现代互联网时代,数据是非常重要的资源。无论是用于商业分析、机器学习还是市场调研,获取数据的能力成为了关键技能之一。其中,网络爬虫(Web Crawler) 是一种自动从网页中提取信息的技术。本文将介绍如何使用 Python 编写一个基础的 Web 爬虫,并结合实际代码进行演示。
什么是网络爬虫?
网络爬虫(Web Crawler),也称为网络蜘蛛(Web Spider)或网页机器人(Web Bot),是一种自动浏览网页并提取有用信息的程序。它通常被搜索引擎用来索引网站内容,也可以用于数据分析、价格监控、舆情分析等场景。
技术选型
我们将使用以下技术栈:
Python 3.xrequests:发起 HTTP 请求BeautifulSoup4:解析 HTML 内容lxml:HTML 解析器(可选)pandas:用于保存数据到 CSV 文件安装依赖包:
pip install requests beautifulsoup4 lxml pandas
项目目标
我们以爬取豆瓣电影 Top250 页面中的电影名称、评分和链接为例,展示如何构建一个完整的爬虫流程。
目标网址:https://movie.douban.com/top250
注意:本示例仅供教学用途,请遵守网站的 robots 协议及法律法规,避免对服务器造成过大压力。
爬虫结构设计
发起请求获取页面 HTML 内容。使用 BeautifulSoup 解析 HTML。提取所需字段(如电影名、评分等)。将结果存储为本地文件(如 CSV 格式)。扩展支持多页抓取。代码实现
5.1 获取单页数据
import requestsfrom bs4 import BeautifulSoupimport timedef fetch_page(url): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36' } response = requests.get(url, headers=headers) if response.status_code == 200: return response.text else: print(f"请求失败,状态码:{response.status_code}") return Nonedef parse_html(html): soup = BeautifulSoup(html, 'lxml') items = soup.find_all('div', class_='item') movies = [] for item in items: title = item.find('span', class_='title').text rating = item.find('span', class_='rating_num').text link = item.find('a')['href'] movies.append({ 'title': title, 'rating': rating, 'link': link }) return moviesdef main(): url = 'https://movie.douban.com/top250' html = fetch_page(url) if html: movies = parse_html(html) for movie in movies: print(movie)if __name__ == '__main__': main()
运行上述代码后,会输出前25部电影的信息,包括名称、评分和链接。
5.2 支持多页抓取
豆瓣 Top250 分为多个页面,每页显示25部电影。我们可以遍历所有页面来获取完整数据。
def get_all_pages(): base_url = 'https://movie.douban.com/top250?start={}' all_movies = [] for i in range(0, 250, 25): # 每页25个,共10页 url = base_url.format(i) print(f"正在抓取第 {i // 25 + 1} 页:{url}") html = fetch_page(url) if html: movies = parse_html(html) all_movies.extend(movies) time.sleep(2) # 避免频繁请求,设置延时 return all_movies
5.3 数据存储到CSV文件
import pandas as pddef save_to_csv(data, filename='douban_top250.csv'): df = pd.DataFrame(data) df.to_csv(filename, index=False, encoding='utf-8-sig') # utf-8-sig 防止 Excel 中文乱码 print(f"数据已保存至 {filename}")def main(): all_movies = get_all_pages() save_to_csv(all_movies)if __name__ == '__main__': main()
反爬机制与应对策略
虽然我们的爬虫简单有效,但实际部署中可能会遇到反爬机制,例如:
IP 被封禁需要登录验证JavaScript 渲染页面请求频率限制常见解决方案包括:
设置请求头(User-Agent)模拟浏览器访问。使用代理IP池。使用 Selenium 或 Playwright 加载动态网页。控制请求频率,加入随机延时。总结
通过本文的学习,你已经掌握了使用 Python 构建一个基本 Web 爬虫的完整流程,包括:
使用requests
发起 HTTP 请求;使用 BeautifulSoup
解析 HTML;多页抓取逻辑;数据清洗与存储;基础反爬策略应对思路。当然,这只是入门级别的爬虫项目。随着需求复杂化,可以进一步扩展如下功能:
使用 Scrapy 框架构建更复杂的爬虫;异步爬虫提升效率;存储到数据库(如 MySQL、MongoDB);自动更新机制;可视化展示爬取结果。希望这篇文章能为你打开数据采集的大门,继续深入探索爬虫的世界!
附录:完整代码
import requestsfrom bs4 import BeautifulSoupimport timeimport pandas as pddef fetch_page(url): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36' } response = requests.get(url, headers=headers) if response.status_code == 200: return response.text else: print(f"请求失败,状态码:{response.status_code}") return Nonedef parse_html(html): soup = BeautifulSoup(html, 'lxml') items = soup.find_all('div', class_='item') movies = [] for item in items: title = item.find('span', class_='title').text rating = item.find('span', class_='rating_num').text link = item.find('a')['href'] movies.append({ 'title': title, 'rating': rating, 'link': link }) return moviesdef get_all_pages(): base_url = 'https://movie.douban.com/top250?start={}' all_movies = [] for i in range(0, 250, 25): # 每页25个,共10页 url = base_url.format(i) print(f"正在抓取第 {i // 25 + 1} 页:{url}") html = fetch_page(url) if html: movies = parse_html(html) all_movies.extend(movies) time.sleep(2) # 避免频繁请求,设置延时 return all_moviesdef save_to_csv(data, filename='douban_top250.csv'): df = pd.DataFrame(data) df.to_csv(filename, index=False, encoding='utf-8-sig') # utf-8-sig 防止 Excel 中文乱码 print(f"数据已保存至 {filename}")def main(): all_movies = get_all_pages() save_to_csv(all_movies)if __name__ == '__main__': main()
如果你喜欢这篇文章,欢迎点赞、收藏或分享给更多人看到!