Python 网络爬虫从入门到实战:全网最详细技术解析_python爬虫教程(非常详细)
一、引言:揭开网络爬虫的神秘面纱
1.1 什么是网络爬虫?
网络爬虫(Web Crawler)是一种按照一定规则,自动抓取万维网信息的程序或脚本。它就像互联网上的 \"蜘蛛\",通过链接关系从一个网页爬到另一个网页,采集需要的数据。
应用场景:
数据采集与分析(市场调研、竞品分析)
搜索引擎(百度、谷歌的网页抓取)
学术研究(文献数据获取)
电商比价(商品价格监控)
1.2 爬虫技术栈全景图
技术分类
核心工具
官方文档链接
数据获取
requests、aiohttp、Scrapy
requests 文档
数据解析
BeautifulSoup、lxml、PyQuery
BeautifulSoup 文档
反爬处理
Selenium、Playwright、代理 IP
Selenium 文档
数据存储
MongoDB、MySQL、CSV
MongoDB 官方文档
1.3爬虫的基本概念
1.3.1网络爬虫(Web Crawler):
本质是模拟浏览器行为,通过 HTTP/HTTPS 协议向服务器发送请求,获取网页内容并解析数据的程序。
1.3.2爬虫的工作流程:
发送请求:向目标网站服务器发送 HTTP 请求
接收响应:获取服务器返回的 HTML/JSON 等格式的页面内容
解析数据:从响应内容中提取所需信息
存储数据:将提取的数据保存到本地(数据库、文件等)
1.4 HTTP 协议与网络请求基础
1.4.1常见 HTTP 请求方法:
◦ GET:获取资源(最常用的爬虫请求方式)
◦ POST:提交数据到服务器
◦ HEAD:获取响应头信息
1.4.2 重要 HTTP 响应状态码:
◦ 200 OK:请求成功,返回页面内容
◦ 403 Forbidden:禁止访问(常见反爬机制)
◦ 404 Not Found:页面不存在
◦ 500 Internal Server Error:服务器错误
1.4.3请求头(Headers)的关键字段:
◦ User-Agent:标识浏览器信息(爬虫需模拟真实浏览器 UA)
◦ Cookie:存储会话信息,用于保持登录状态
◦ Referer:标识请求来源页面
二、环境搭建:工欲善其事必先利其器
2.1 安装 Python 环境
推荐使用 Python 3.8 + 版本,通过官网下载安装包:Python 官方下载地址
安装完成后,在命令行验证:
python --version
# 输出类似:Python 3.9.7
2.2 安装核心爬虫库
# 基础库
pip install requests beautifulsoup4 lxml
# 进阶库
pip install scrapy selenium playwright
# 数据存储
pip install pymongo pandas
2.3 开发工具推荐
PyCharm:专业 Python IDE,支持调试和代码补全
VS Code:轻量级编辑器,安装 Python 插件后体验极佳
Charles/Fiddler:抓包工具,分析网络请求流程
2.4 Python 爬虫常用库与工具
2.4.1 网络请求库:requests
requests
是 Python 中最常用的 HTTP 请求库,支持丰富的请求参数和自定义设置:
没有安装requests库的可以在终端安装:
代码:
import requests# 发送GET请求response = requests.get(\"https://example.com\", headers={ \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\", \"Accept\": \"text/html,application/xhtml+xml\" })# 检查响应状态if response.status_code == 200: # 获取文本内容(自动解码) html_content = response.text # 获取二进制内容(用于图片、文件下载) binary_content = response.contentelse: print(f\"请求失败,状态码:{response.status_code}\")
2.4.2 解析库:BeautifulSoup 与 lxml
2.4.2_1 BeautifulSoup:简单易用的 HTML 解析器
from bs4 import BeautifulSoup# 解析HTML内容soup = BeautifulSoup(html_content, \'html.parser\')# 通过标签名查找元素title = soup.title.text# 通过类名查找元素articles = soup.find_all(\'div\', class_=\'article-item\')# 通过CSS选择器查找元素links = soup.select(\'a.read-more\')
2.4.2_2 lxml:高效的 XML/HTML 解析器(性能优于 BeautifulSoup)
from lxml import etree# 解析HTMLhtml_tree = etree.HTML(html_content)# 使用XPath表达式提取数据title = html_tree.xpath(\'//title/text()\')[0]article_titles = html_tree.xpath(\'//div[@class=\"article-item\"]/h3/a/text()\')article_links = html_tree.xpath(\'//div[@class=\"article-item\"]/h3/a/@href\')
2.4.3 正则表达式:re 模块
正则表达式适用于复杂文本模式的匹配,常用于提取非结构化数据:
import re# 提取所有URLurls = re.findall(r\'https?://[^\\s/$.?#].[^\\s]*\', html_content)# 提取邮箱地址emails = re.findall(r\'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\', html_content)# 提取电话号码(示例:中国大陆手机号)phones = re.findall(r\'1[3-9]\\d{9}\', html_content)
2.4.4 异步爬虫:aiohttp 与 asyncio
对于高并发爬取场景,异步编程可大幅提升效率:
import asyncioimport aiohttpasync def fetch(url, session): try: async with session.get(url, timeout=10) as response: if response.status == 200: return await response.text() except Exception as e: print(f\"请求出错:{url}, 错误:{e}\") return Noneasync def main(urls): async with aiohttp.ClientSession(headers={ \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\" }) as session: tasks = [fetch(url, session) for url in urls] results = await asyncio.gather(*tasks, return_exceptions=True) return results# 调用示例urls = [\"https://example.com/page1\", \"https://example.com/page2\", ...]loop = asyncio.get_event_loop()htmls = loop.run_until_complete(main(urls))
三、基础爬虫开发:从 requests 到数据解析
3.1入门程序:
3.1.1 首先清华镜像网址安装selenium库:
pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple
from selenium import webdriverfrom selenium.webdriver.common.by import Bydriver = webdriver.Chrome()url = \'https://www.baidu.com/\'driver.get(url) # 打开百度首页driver.maximize_window() # 将浏览器最大化# 找到搜索框元素,搜索框的 id 为\"kw\"search_box = driver.find_element(By.ID, \"kw\")# 在搜索框中输入查询内容search_box.send_keys(\"csdn博客\")# 模拟点击搜索按钮,搜索按钮的 id 为\"su\"search_button = driver.find_element(By.ID, \"su\")search_button.click()
3.2 发送 HTTP 请求(以豆瓣电影 Top250 为例)
3.2.1 分析目标网站
豆瓣电影 Top250 页面结构特点:
- 分页 URL 规律:
https://movie.douban.com/top250?start=25&filter=
(start 参数控制页码,每次增加 25) - 电影信息包含在
class=\"grid_view\"
的ol
标签下的li
元素中 - 需提取字段:电影名称、评分、导演、主演、上映时间、简介
完整爬虫代码
import requestsfrom bs4 import BeautifulSoupimport timeimport randomimport csvimport os# 配置请求头(模拟浏览器)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\", \"Accept\": \"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\", \"Accept-Language\": \"zh-CN,zh;q=0.9,en;q=0.8\", \"Connection\": \"keep-alive\"}# 存储数据的列表movies_data = []def get_movie_info(url): \"\"\"获取单页电影信息\"\"\" try: # 发送请求,添加随机延迟避免频繁请求 time.sleep(random.uniform(1, 3)) response = requests.get(url, headers=headers) response.raise_for_status() # 抛出HTTP错误 response.encoding = response.apparent_encoding # 自动检测编码 # 解析HTML soup = BeautifulSoup(response.text, \'html.parser\') movie_list = soup.find(\'ol\', class_=\'grid_view\').find_all(\'li\') for movie in movie_list: # 提取电影信息 movie_info = {} movie_info[\'rank\'] = movie.find(\'em\').text # 排名 movie_info[\'title\'] = movie.find(\'span\', class_=\'title\').text # 标题 # 处理可能存在的副标题 subtitle = movie.find(\'span\', class_=\'other\') movie_info[\'title\'] += subtitle.text if subtitle else \"\" # 提取导演、主演等信息 info_div = movie.find(\'div\', class_=\'bd\') movie_info[\'info\'] = info_div.p.text.strip() # 导演、主演、年份等信息 # 提取评分 movie_info[\'rating\'] = movie.find(\'span\', class_=\'rating_num\').text # 提取评价人数 movie_info[\'votes\'] = movie.find(\'span\', class_=\'pl\').text.strip(\'人评价\') # 提取简介 quote = movie.find(\'span\', class_=\'inq\') movie_info[\'quote\'] = quote.text if quote else \"暂无简介\" movies_data.append(movie_info) print(f\"已获取:{movie_info[\'title\']}\") except Exception as e: print(f\"获取页面{url}出错:{e}\")def main(): \"\"\"主函数:爬取所有页面并保存数据\"\"\" base_url = \"https://movie.douban.com/top250\" # 创建存储目录 if not os.path.exists(\"douban_movies\"): os.makedirs(\"douban_movies\") # 爬取10页数据(Top250) for start in range(0, 250, 25): page_url = f\"{base_url}?start={start}&filter=\" print(f\"正在爬取页面:{page_url}\") get_movie_info(page_url) # 保存数据到CSV文件 csv_file = os.path.join(\"douban_movies\", \"douban_top250.csv\") with open(csv_file, \'w\', newline=\'\', encoding=\'utf-8-sig\') as f: fieldnames = [\'rank\', \'title\', \'info\', \'rating\', \'votes\', \'quote\'] writer = csv.DictWriter(f, fieldnames=fieldnames) writer.writeheader() writer.writerows(movies_data) print(f\"爬取完成!共获取{len(movies_data)}条电影信息,已保存至{csv_file}\")if __name__ == \"__main__\": main()
import requests
url = \"https://movie.douban.com/top250\"
headers = {
\"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36\"
}
response = requests.get(url, headers=headers)
print(f\"状态码:{response.status_code}\") # 200表示请求成功
print(f\"编码格式:{response.encoding}\") # 查看网页编码
3.3解析 HTML 内容(使用 BeautifulSoup)
from bs4 import BeautifulSoup
soup = BeautifulSoup(response.text, \"lxml\")
movie_list = soup.find(\"ol\", class_=\"grid_view\").find_all(\"li\")
for movie in movie_list:
title = movie.find(\"span\", class_=\"title\").text # 电影名称
rating = movie.find(\"span\", class_=\"rating_num\").text # 评分
print(f\"电影名称:{title},评分:{rating}\")
3.4 提取数据的三种方式对比
解析方式
优点
缺点
适用场景
BeautifulSoup
简单易用,支持多种解析器
速度较慢
快速原型开发
lxml
解析速度快,支持 XPath
学习成本较高
大规模数据解析
正则表达式
灵活性强
复杂网页难以维护
特定模式匹配
四、反爬机制应对:爬虫与网站的攻防博弈
4.1 基础反爬手段破解
(1)User-Agent 伪装(设置随机请求头)
# 随机User-Agent生成器(使用fake_useragent库)
from fake_useragent import UserAgent
ua = UserAgent()
headers = {\"User-Agent\": ua.random}
(2)IP 代理池搭建(使用代理IP)
# 示例:使用代理IP发送请求
proxies = {
\"http\": \"http://proxy.example.com:8080\",
\"https\": \"https://proxy.example.com:8080\"
}
response = requests.get(url, headers=headers, proxies=proxies)
重要注意事项
-
遵守robots.txt协议
-
设置合理的请求间隔(time.sleep)
-
避免对目标网站造成过大压力
-
注意法律合规性
4.2 JavaScript 渲染页面处理
当遇到动态加载数据(如滚动加载、AJAX 请求)时,需要使用浏览器自动化工具:
# Selenium+Chrome示例
from selenium import webdriver
driver = webdriver.Chrome()
driver.get(\"https://example.com/dynamic-page\")
# 等待页面加载
driver.implicitly_wait(10)
html = driver.page_source
driver.quit()
4.3 Cookies 处理与登录态保持
# 使用Session对象保持会话
session = requests.Session()
login_url = \"https://example.com/login\"
session.post(login_url, data=login_data, headers=headers)
# 登录后访问需要权限的页面
response = session.get(protected_url, headers=headers)
五、实战案例
5.1:爬取豆瓣电影短评(单页为例)
5.1.1 需求分析
抓取指定博主的所有博客文章,获取以下信息:
用户名、点赞数量、评论时间、爬取IP地、评论内容
5.1.2代码实现过程
1、爬取数据并生成bs对象
from bs4 import BeautifulSoupimport requestsimport pandas as pdurl = \'https://movie.douban.com/subject/30181250/comments?status=P\'headers = { \'User-Agent\': \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36\'}response = requests.get(url, headers=headers)html_str = response.textprint(html_str)
打印结果:
2、开发者工具中分析网页结构,定位短评数据在html中的位置
3、爬取用户名
#3、爬取用户名list_name = [a.string for a in soup.select(\'.comment-info a\')]print(len(list_name))print(list_name)
4、爬取点赞数量
# 点赞list_votes = [span.string.strip() for span in soup.select(\'.votes\')]len(list_votes)print(list_votes)
5、爬取评论时间
# 时间list_time = [span.string.strip() for span in soup.select(\'.comment-time\')]len(list_time)print(list_time)
6、 爬取IP地
#爬取IP地# ip地list_location = [span.string.strip() for span in soup.select(\'.comment-location\')]len(list_location)print(list_location)
7、 爬取评论内容
#爬取评论内容list_content = [i.string.strip() for i in soup.select(\'.comment-content .short\')]print(len(list_content))print(list_content)
8、 生成表格对象
# 生成表格对象import pandas as pddf = pd.DataFrame({ \'用户名\': list_name, \'时间\': list_time, \'ip地\': list_location, \'点赞数\': list_votes, \'短评内容\': list_content})df
9、数据存储
# 存储到MySQL
from sqlalchemy import create_engine
engine = create_engine(\'mysql+pymysql://root:123456(密码)@localhost:3306/data(数据库名)\')
df.to_sql(\'currency1\', engine, index=False, if_exists=\'replace\')
print(\"数据存储成功\")
5.1.3 爬取豆瓣电影短评完整代码(封装函数:包含翻页爬取)
import timefrom bs4 import BeautifulSoupimport requestsimport pandas as pdfrom sqlalchemy import create_engine# 爬取单页数据函数def get_one_page(url,database,table): \'\'\' url: 某电影的豆瓣短评页面url table_name: mysql数据库中存储爬取到的数据的表的名称 \'\'\' print(\'待爬取url:\', url) # 爬取数据,并生成bs对象 headers = { \'User-Agent\': \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36\' } response = requests.get(url, headers=headers) html_str = response.text soup = BeautifulSoup(html_str, \'lxml\') # 数据解析 soup = BeautifulSoup(html_str, \'lxml\') list_name = [a.string for a in soup.select(\'.comment-info a\')] list_time = [span.string.strip() for span in soup.select(\'.comment-time\')] list_location = [span.string.strip() for span in soup.select(\'.comment-location\')] list_votes = [span.string.strip() for span in soup.select(\'.votes\')] list_content = [i.string.strip() for i in soup.select(\'.comment-content .short\')] # print(len(list_name)) # print(len(list_time)) # print(len(list_location)) # print(len(list_votes)) # print(len(list_content)) df = pd.DataFrame({ \'用户名\': list_name, \'点赞数量\': list_votes, \'时间\': list_time, \'IP地\': list_location, \'短评内容\': list_content }) print(\'当前页数据爬取解析完毕\\n\', df) #数据储存 engine = create_engine(f\'mysql+pymysql://root:123456@localhost:3306/{database}\') df.to_sql(table, engine, index=False, if_exists=\'append\') print(\'当前页数据导入MySQL完毕...\')# 爬取多页数据def get_more_page(url, database, table, max_page): \'\'\' url: 某电影的豆瓣短评首页url\\n database: 数据保存的mysql数据库名\\n table: 数据保存的mysql表名\\n max_page: 你要爬取的总页数 \'\'\' # 爬取首页数据 get_one_page(url, database, table) # 再爬第2页到第max_page页 for i in range(2, max_page + 1): url_new = url[:url.find(\'?\')+1] + f\'start={20*(i-1)}&limit=20&status=P&sort=new_score\' get_one_page(url_new, database, table) if __name__ == \'__main__\': url = \'https://movie.douban.com/subject/30181250/comments?status=P\' # database = \'hjw\' # table = \'fengshen2\' # get_one_page(url,database,table) get_more_page(url,\'hjw\',\'fengshen2\',5)
5.4.3运行结果展示
六、进阶技巧:分布式爬虫与效率优化
6.1 异步爬虫(aiohttp 实现)
import aiohttp
import asyncio
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main(urls):
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
results = await asyncio.gather(*tasks)
return results
if __name__ == \"__main__\":
urls = [\"https://example.com/page1\", \"https://example.com/page2\", ...] # 100个URL
asyncio.run(main(urls))
6.2 Scrapy 框架使用
# items.py定义数据结构
import scrapy
class BlogItem(scrapy.Item):
title = scrapy.Field()
link = scrapy.Field()
read_count = scrapy.Field()
# spider文件
class CsdnSpider(scrapy.Spider):
name = \"csdn_spider\"
start_urls = [\"https://blog.csdn.net/your_username?page=1\"]
def parse(self, response):
for article in response.css(\"div.article-item-box\"):
yield {
\"title\": article.css(\"h4 a::text\").get(),
\"link\": response.urljoin(article.css(\"h4 a::attr(href)\").get()),
\"read_count\": article.css(\"div.article-bar-bottom span:nth-child(1)::text\").get()
}
# 处理分页
next_page = response.css(\"a.next-page::attr(href)\").get()
if next_page:
yield response.follow(next_page, self.parse)
6.3 分布式爬虫架构
推荐使用Scrapy-Redis实现分布式爬取,架构图如下:
七、合规与伦理:做有道德的爬虫工程师
7.1 法律风险提示
遵守网站的robots.txt协议(如https://example.com/robots.txt)
避免抓取用户隐私数据(手机号、身份证号等)
控制请求频率,防止影响网站正常运行
7.2 文明爬虫规范
添加请求间隔(time.sleep(1))
尊重网站版权,不滥用爬取数据
遇到反爬措施时,优先通过合法渠道获取数据
八、总结与展望:爬虫技术的未来
8.1 核心知识回顾
网络爬虫的基本原理与技术栈
从 requests 到 Scrapy 的开发进阶
反爬机制的应对策略
实战案例的完整开发流程
8.2 技术发展趋势
AI 驱动爬虫:结合 NLP 识别动态内容
无代码爬虫工具:降低技术门槛
区块链反爬:数据加密技术的新挑战
8.3 学习路线和资源推荐
学习路线推荐:HTML/CSS基础 → 2. HTTP协议 → 3. 正则表达式 → 4. Scrapy框架
推荐资源:
官方文档:永远的第一手资料
BeautifulSoup中文文档
Scrapy框架实战教程
技术博客:CSDN 爬虫专栏
相关专栏推荐 ➡️ Python爬虫进阶技巧
开源项目:Awesome Crawlers
源码获取 ➡️ GitHub仓库地址
如果您在实践过程中遇到问题,欢迎在评论区留言交流!让我们一起探索数据世界的无限可能~