Python 爬虫教程之爬取小说
一、Python 爬虫基础知识
1.1、爬虫概念
Python 爬虫是指使用 Python 编写的程序,自动从互联网收集数据的技术。它通常用于数据采集、信息监控、网站测试等场景。
1.2、 爬虫的基本流程
- 发送请求:使用 HTTP 请求从目标网站获取网页数据。
- 解析响应:对获取到的网页数据进行解析。
- 提取数据:从解析后的数据中提取有用的信息。
- 存储数据:将提取的数据保存到文件或数据库中。
- 处理异常:处理可能出现的错误或异常情况。
1.3、常用库
- requests:发送 HTTP 请求。
- BeautifulSoup:解析 HTML 和 XML 文档。
- lxml:用于解析 HTML 和 XML。
- Selenium:自动化浏览器操作,用于处理动态页面。
- Playwright:现代化的浏览器自动化库,支持多种浏览器。
1.4、基础示例代码
import requests
from bs4 import BeautifulSoup
# 目标网址
url = 'https://example.com/novel'
# 发送 GET 请求获取网页内容
response = requests.get(url)
response.encoding = 'utf-8' # 设置网页编码为 UTF-8
# 解析 HTML 页面
soup = BeautifulSoup(response.text, 'html.parser')
# 提取小说内容(假设内容在 class 为 'novel-text' 的 div 中)
novel_content = soup.find('div', class_='novel-text').get_text()
# 将内容保存到 TXT 文件
with open('novel.txt', 'w', encoding='utf-8') as file:
file.write(novel_content)
1.5、爬虫注意事项
- 合法性:遵循 robots.txt 文件和网站使用条款。
- 请求频率:避免对服务器造成负担,设置合适的请求间隔。
- 数据存储:确保数据存储格式的正确性和一致性。
- 隐私:尊重用户隐私,不抓取敏感信息。
二、爬取百度小说章节标题和内容
2.1、代码示例
import requests
from bs4 import BeautifulSoup
def fetch_chapter_titles_and_contents(novel_url):
# 发送请求获取小说主页
response = requests.get(novel_url)
response.encoding = 'utf-8'
# 解析小说主页
soup = BeautifulSoup(response.text, 'html.parser')
chapters = [] # 用于存储章节标题和内容的列表
# 遍历页面中的章节链接
for item in soup.find_all('a', class_='chapter-link'):
title = item.get_text() # 获取章节标题
href = item.get('href') # 获取章节链接
chapter_url = f"https://example.com{href}" # 构造完整的章节 URL
# 请求章节页面
chapter_response = requests.get(chapter_url)
chapter_response.encoding = 'utf-8'
chapter_soup = BeautifulSoup(chapter_response.text, 'html.parser')
content = chapter_soup.find('div', class_='chapter-content').get_text() # 获取章节内容
# 将标题和内容添加到列表中
chapters.append((title, content))
# 保存章节标题和内容到 TXT 文件
with open('novel_chapters.txt', 'w', encoding='utf-8') as file:
for title, content in chapters:
file.write(f"Chapter: {title}\n")
file.write(f"Content:\n{content}\n\n")
# 调用函数抓取章节
novel_url = 'https://example.com/novel'
fetch_chapter_titles_and_contents(novel_url)
2.2、代码解释
- 请求小说主页:获取小说的章节列表页面。
- 解析章节链接:提取每个章节的标题和链接。
- 请求章节页面:对每个章节链接发起请求,获取内容。
- 保存到文件:将标题和内容写入到文本文件中。
以上代码示例注释也比较清晰明了,大家多参考。
三、处理 JavaScript 动态加载的页面
处理 JavaScript 动态加载页面的逻辑涉及到与传统静态页面的抓取有所不同,因为这些页面的内容通常通过 JavaScript 在页面加载后动态生成,所以使用Selenium 和 Playwright 等工具来处理这些页面。
3.1、使用 Selenium
示例代码:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
import time
from bs4 import BeautifulSoup
# 配置 Selenium WebDriver
options = Options()
options.add_argument("--headless") # 启用无头模式,不弹出浏览器窗口
service = Service('/path/to/chromedriver') # 替换为你本地的 chromedriver 路径
driver = webdriver.Chrome(service=service, options=options)
# 打开目标网址
driver.get('https://example.com/dynamic-page')
# 等待 JavaScript 内容加载完成
time.sleep(5) # 等待时间根据实际情况调整
# 获取页面源代码
page_source = driver.page_source
# 解析页面内容
soup = BeautifulSoup(page_source, 'html.parser')
# 提取小说内容(假设内容在 class 为 'novel-text' 的 div 中)
novel_content = soup.find('div', class_='novel-text').get_text()
# 将内容保存到 TXT 文件
with open('novel.txt', 'w', encoding='utf-8') as file:
file.write(novel_content)
# 关闭浏览器
driver.quit()
3.2、使用 Playwright
示例代码:
from playwright.sync_api import sync_playwright
def fetch_dynamic_content(url):
with sync_playwright() as p:
# 启动 Chromium 浏览器
browser = p.chromium.launch(headless=True)
page = browser.new_page() # 新建页面
page.goto(url) # 访问目标网址
page.wait_for_timeout(5000) # 等待 5 秒以确保内容加载完毕
# 获取页面内容
content = page.content()
browser.close() # 关闭浏览器
# 解析页面内容
soup = BeautifulSoup(content, 'html.parser')
novel_content = soup.find('div', class_='novel-text').get_text()
# 将内容保存到 TXT 文件
with open('novel.txt', 'w', encoding='utf-8') as file:
file.write(novel_content)
# 调用函数抓取动态内容
fetch_dynamic_content('https://example.com/dynamic-page')
3.3、结合 BeautifulSoup 和 Selenium
示例代码:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from bs4 import BeautifulSoup
import time
# 配置 Selenium WebDriver
options = Options()
options.add_argument("--headless")
service = Service('/path/to/chromedriver')
driver = webdriver.Chrome(service=service, options=options)
# 打开目标网址
driver.get('https://example.com/dynamic-page')
# 等待 JavaScript 内容加载完成
time.sleep(5)
# 获取页面源代码
page_source = driver.page_source
# 解析页面内容
soup = BeautifulSoup(page_source, 'html.parser')
# 提取小说内容
novel_content = soup.find('div', class_='novel-text').get_text()
# 保存内容到 TXT 文件
with open('novel.txt', 'w', encoding='utf-8') as file:
file.write(novel_content)
# 关闭浏览器
driver.quit()
3.4、处理 AJAX 请求
示例代码:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
import time
# 配置 Selenium WebDriver
options = Options()
options.add_argument("--headless")
service = Service('/path/to/chromedriver')
driver = webdriver.Chrome(service=service, options=options)
# 打开目标网址
driver.get('https://example.com/ajax-page')
# 找到并点击“加载更多”按钮
button = driver.find_element(By.ID, 'load-more')
button.click()
# 等待 AJAX 请求加载新内容
time.sleep(5)
# 获取页面源代码
page_source = driver.page_source
# 将内容保存到 TXT 文件
with open('ajax_content.txt', 'w', encoding='utf-8') as file:
file.write(page_source)
# 关闭浏览器
driver.quit()
四、错误处理
4.1、常见错误
- 网络错误:检查网络连接和目标网址的可达性。
- 解析错误:检查 HTML 结构是否发生变化,确保解析器的选择器正确。
- 超时错误:增加请求超时设置,或优化等待时间。
- 权限错误:处理网站的 403 Forbidden 或 401 Unauthorized错误,检查请求头和访问权限。
import requests
url = 'https://example.com/novel'
try:
# 发送请求并设置超时
response = requests.get(url, timeout=10)
response.raise_for_status() # 抛出 HTTP 错误
# 处理响应内容
print(response.text)
except requests.Timeout:
print("请求超时,请检查网络连接或目标网站的响应时间。")
except requests.RequestException as e:
print(f"请求错误: {e}")
五、免责声明
- 内容准确性:本博客中的所有信息和内容仅供参考之用。尽管作者尽力确保所提供的信息准确无误,但不对其准确性、完整性或适用性作出任何明示或暗示的保证。作者不对因依赖或使用本博客内容而导致的任何直接或间接损失或损害负责。
- 版权声明:本博客中的所有内容,包括文字、图片和代码,均为作者原创或引用自公开的资源。若涉及到版权问题或引用的内容不符合版权规定,请及时联系作者以做出相应的处理。未经授权,禁止以任何形式复制、转载或商业使用本博客内容。
- 个人观点: 本博客中的观点和见解仅代表作者个人的观点,并不代表 CSDN或其他机构的观点。作者在博客中分享的技术知识和经验基于个人的学习和实践,读者在应用这些信息时需自行判断和承担风险。
- 法律责任:作者不对因使用本博客中的信息而产生的任何法律责任或纠纷承担责任。读者在依赖本博客内容时应自行进行充分的验证,并遵守相关的法律法规。
- 网站链接:本博客可能包含指向其他网站的链接,这些链接仅为方便读者而提供。作者不对这些网站的内容、准确性或可靠性负责。访问这些链接时,读者需自行承担风险。
- 技术变更: 由于技术和信息更新的速度,本博客中的技术信息和建议可能会有所变化。作者不对因技术变更或信息更新造成的任何问题或损失负责。
- 联系信息: 如果您对本博客内容有任何疑问或建议,欢迎通过作者提供的联系方式与作者沟通。作者会尽力解答您的问题并做出适当的修正。