杰瑞科技汇

Python爬虫如何结合Gitbook使用?

下面我将为你提供一个详细的、分步的指南,从基础到进阶,教你如何用 Python 爬取一本 GitBook。

Python爬虫如何结合Gitbook使用?-图1
(图片来源网络,侵删)

GitBook 内容特点分析

在开始之前,我们先要了解 GitBook 的内容是如何组织的:

  1. 静态 HTML:GitBook 的章节列表(目录)和大部分章节的正文内容是静态 HTML,这意味着我们可以直接发送 HTTP 请求来获取这些页面。
  2. 动态加载(部分内容):有些 GitBook 的内容(如代码块的行号、部分交互元素)可能是通过 JavaScript 动态加载的,但对于纯文本内容,我们通常不需要渲染整个页面。
  3. 反爬机制
    • User-Agent 检测:服务器会检查请求的 User-Agent(浏览器标识),如果是一个简单的 Python 脚本,很容易被识别为爬虫。
    • 请求频率限制:如果你在短时间内发送大量请求,GitBook 服务器可能会暂时封禁你的 IP 地址。
  4. 内容存储:GitBook 的内容通常存储在 https://<book-name>.gitbook.io/<book-path>/ 这样的路径下,每个章节的 URL 都有其特定的规律。

第一步:准备工作

安装必要的库

我们将使用 requests 库来发送 HTTP 请求,BeautifulSoup 库来解析 HTML,以及 lxml 作为解析器(速度更快)。

pip install requests beautifulsoup4 lxml

选择目标 GitBook

我们以一本公开的 GitBook 为例,gitbook tutorial 官方文档:https://docs.gitbook.com/

我们的目标是爬取它的所有章节内容,并保存到本地文件中。

Python爬虫如何结合Gitbook使用?-图2
(图片来源网络,侵删)

第二步:基础爬虫(爬取单章内容)

我们先从一个简单的目标开始:爬取一个指定章节的纯文本内容。

import requests
from bs4 import BeautifulSoup
import re
def get_chapter_content(url):
    """
    获取 GitBook 单个章节的纯文本内容
    """
    # 1. 设置请求头,模拟浏览器
    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'
    }
    try:
        # 2. 发送 HTTP 请求
        response = requests.get(url, headers=headers, timeout=10)
        # 3. 检查请求是否成功
        response.raise_for_status()  # 如果状态码不是 200,则抛出异常
        # 4. 使用 BeautifulSoup 解析 HTML
        soup = BeautifulSoup(response.text, 'lxml')
        # 5. 定位到内容区域
        # 在 GitBook 中,正文内容通常在 class 为 "markdown-section" 的 div 中
        content_div = soup.find('div', class_='markdown-section')
        if content_div:
            # 6. 提取文本并清理
            # .get_text() 可以获取一个标签下的所有文本,包括子标签中的
            # strip() 用于去除首尾多余的空白字符
            text = content_div.get_text(separator='\n', strip=True)
            # 可选:使用正则表达式清理多余的空白行
            cleaned_text = re.sub(r'\n\s*\n', '\n\n', text)
            return cleaned_text
        else:
            print(f"在 {url} 中未找到 'markdown-section' 容器。")
            return None
    except requests.exceptions.RequestException as e:
        print(f"请求 {url} 时发生错误: {e}")
        return None
# --- 测试 ---
if __name__ == '__main__':
    # 替换成你想要爬取的章节 URL
    test_url = "https://docs.gitbook.com/getting-started"
    content = get_chapter_content(test_url)
    if content:
        print(f"成功获取内容,长度: {len(content)} 字符")
        # 打印前 500 个字符预览
        print("\n--- 内容预览 ---\n")
        print(content[:500])

代码解释

  1. headers:我们设置了一个 User-Agent,让服务器以为我们的请求来自一个真实的浏览器,这是绕过最基础反爬的关键。
  2. requests.get():发送 GET 请求获取网页源代码。
  3. response.raise_for_status():这是一种良好的实践,如果请求失败(如 404, 500),它会抛出异常。
  4. BeautifulSoup(response.text, 'lxml'):将 HTML 内容解析成一个可操作的对象。
  5. soup.find('div', class_='markdown-section'):这是最关键的一步,我们通过 CSS 选择器定位到包含正文内容的 <div> 标签,你可以通过浏览器“开发者工具”(F12)来验证这个选择器是否正确。
  6. .get_text():提取解析后的对象中的所有文本。

第三步:进阶爬虫(爬取整本书)

现在我们知道如何爬取单章内容,接下来要爬取整本书,我们需要:

  1. 获取书籍的目录页。
  2. 从目录页中解析出所有章节的链接。
  3. 遍历这些链接,调用我们上面写的函数获取每一章的内容,保存到本地文件。
import requests
from bs4 import BeautifulSoup
import os
import re
import time
# --- 复用上面的 get_chapter_content 函数 ---
def get_chapter_content(url):
    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'
    }
    try:
        response = requests.get(url, headers=headers, timeout=10)
        response.raise_for_status()
        soup = BeautifulSoup(response.text, 'lxml')
        content_div = soup.find('div', class_='markdown-section')
        if content_div:
            text = content_div.get_text(separator='\n', strip=True)
            cleaned_text = re.sub(r'\n\s*\n', '\n\n', text)
            return cleaned_text
        return None
    except requests.exceptions.RequestException as e:
        print(f"请求 {url} 时发生错误: {e}")
        return None
def scrape_gitbook(book_url, output_dir='gitbook_content'):
    """
    爬取整本 GitBook 并保存到本地文件夹
    """
    # 1. 创建输出目录
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
        print(f"已创建目录: {output_dir}")
    # 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'
    }
    try:
        response = requests.get(book_url, headers=headers, timeout=10)
        response.raise_for_status()
    except requests.exceptions.RequestException as e:
        print(f"无法获取书籍目录页 {book_url}: {e}")
        return
    # 3. 解析章节链接
    soup = BeautifulSoup(response.text, 'lxml')
    # 在 GitBook 中,章节链接通常在 class 为 "anchor" 的 <a> 标签里
    # 我们可以通过父级元素来更精确地定位,'li' 或 'div.chapter-item'
    chapter_links = soup.select('div[class*="chapter-item"] a.anchor, li a.anchor')
    if not chapter_links:
        print("在目录页中未找到任何章节链接,请检查选择器是否正确。")
        return
    print(f"找到 {len(chapter_links)} 个章节,开始爬取...")
    # 4. 遍历并爬取每个章节
    for i, link in enumerate(chapter_links):
        chapter_title = link.get_text(strip=True)
        chapter_url = link.get('href')
        # 处理相对 URL
        if chapter_url.startswith('/'):
            chapter_url = f"https://docs.gitbook.com{chapter_url}"
        print(f"正在爬取 [{i+1}/{len(chapter_links)}]: {chapter_title} ({chapter_url})")
        # 获取内容
        content = get_chapter_content(chapter_url)
        if content:
            # 清理文件名,移除非法字符
            safe_title = re.sub(r'[\\/*?:"<>|]', "", chapter_title)
            file_path = os.path.join(output_dir, f"{safe_title}.txt")
            # 保存到文件
            try:
                with open(file_path, 'w', encoding='utf-8') as f:
                    f.write(f"# {chapter_title}\n\n")
                    f.write(content)
                print(f"  -> 已保存到: {file_path}")
            except IOError as e:
                print(f"  -> 写入文件失败: {e}")
        else:
            print(f"  -> 跳过: 未能获取内容。")
        # 5. 礼貌性等待,避免请求过快
        # time.sleep(1) # 可以根据需要调整等待时间
    print("\n爬取任务完成!")
# --- 运行 ---
if __name__ == '__main__':
    # 替换成你想要爬取的 GitBook 根目录 URL
    target_book_url = "https://docs.gitbook.com/"
    scrape_gitbook(target_book_url)

进阶代码解释

Python爬虫如何结合Gitbook使用?-图3
(图片来源网络,侵删)
  1. scrape_gitbook():这是主函数,协调整个爬取过程。
  2. os.makedirs():用于创建保存内容的文件夹。
  3. soup.select(...):这是 BeautifulSoup 的 CSS 选择器功能,非常强大,我们用它来找到所有章节的链接,选择器 'div[class*="chapter-item"] a.anchor' 会查找所有 class 属性中包含 "chapter-item" 的 div 下的 a 标签,并且这个 a 标签的 class 包含 "anchor",这比 find 更灵活,能匹配多个元素。
  4. 处理相对 URL:目录页中的链接可能是 /getting-started 这样的相对路径,我们需要将其拼接成完整的 https://... URL。
  5. enumerate():获取索引和元素,方便我们显示进度。
  6. 文件名安全处理re.sub(r'[\\/*?:"<>|]', "", chapter_title) 移除了 Windows 文件名中不允许的字符。
  7. time.sleep():在每次请求之间加入短暂等待,这是对服务器的基本礼貌,可以有效避免被封禁。

第四步:处理更复杂的情况(动态加载)

有些 GitBook 的内容(如代码高亮、图表)可能依赖于 JavaScript,对于这类情况,requestsBeautifulSoup 可能无法获取到最终渲染的 HTML。

这时,我们需要使用 SeleniumPlaywright 这样的浏览器自动化工具,它们可以像真人一样打开一个浏览器,加载页面,等待 JavaScript 执行完毕后再获取源代码。

使用 Selenium 的示例

  1. 安装 Selenium 和浏览器驱动

    pip install selenium

    你还需要下载对应浏览器的驱动程序,ChromeDriver,并确保它在你的系统路径中,或者通过代码指定其路径。

  2. 修改爬虫代码

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from bs4 import BeautifulSoup
import time
# ... (其他函数保持不变) ...
def get_chapter_content_selenium(url):
    """
    使用 Selenium 获取可能包含动态内容的章节
    """
    # 1. 配置 Selenium
    # 你需要下载好 chromedriver 并指定其路径
    # service = Service(executable_path='path/to/your/chromedriver')
    # driver = webdriver.Chrome(service=service)
    # 或者如果你的 chromedriver 在 PATH 中
    options = webdriver.ChromeOptions()
    # options.add_argument('--headless') # 无头模式,不显示浏览器窗口
    driver = webdriver.Chrome(options=options)
    try:
        # 2. 打开页面
        driver.get(url)
        # 3. 等待 JavaScript 渲染
        # 可以等待一个特定的元素加载完成,或者简单等待几秒
        # 这里我们简单等待 3 秒
        time.sleep(3) 
        # 4. 获取渲染后的页面源代码
        page_source = driver.page_source
        # 5. 使用 BeautifulSoup 解析
        soup = BeautifulSoup(page_source, 'lxml')
        content_div = soup.find('div', class_='markdown-section')
        if content_div:
            text = content_div.get_text(separator='\n', strip=True)
            return text
        return None
    finally:
        # 6. 关闭浏览器
        driver.quit()
# 在你的主爬虫函数中,将 get_chapter_content 替换为 get_chapter_content_selenium
# scrape_gitbook(book_url, output_dir='gitbook_content_selenium')

Selenium 的优缺点

  • 优点:可以处理任何动态加载的内容,爬取效果最接近真实用户。
  • 缺点
    • 速度慢,因为要启动一个完整的浏览器。
    • 资源消耗大。
    • 配置相对复杂(需要管理浏览器驱动)。
    • 容易被更高级的反爬策略检测。

总结与最佳实践

  1. 首选 requests + BeautifulSoup:对于大多数 GitBook,静态解析已经足够,这是最快、最轻量的方案。
  2. 设置 User-Agent:这是爬虫的“身份证”,必须设置。
  3. 控制请求频率:使用 time.sleep() 给服务器喘息的时间,避免被封 IP。
  4. 错误处理:网络请求随时可能失败,使用 try...except 来捕获异常,使你的脚本更健壮。
  5. 分析目标:在写爬虫前,先用浏览器开发者工具(F12)仔细分析目标网页的结构,找到最稳定、最精确的 CSS 选择器。
  6. 尊重 robots.txt:虽然 GitBook 的 robots.txt 通常允许爬取,但这是一个好习惯,你可以访问 https://docs.gitbook.com/robots.txt 来查看规则。
  7. 合法合规:爬取数据前,请确保目标网站允许你这么做,并且不要用于商业用途或对服务器造成过大压力。

希望这个详细的指南能帮助你成功爬取你想要的 GitBook 内容!

分享:
扫描分享到社交APP
上一篇
下一篇