Notion文章简单下载【爬虫单个/批量】——Python+selenium

目录

Notion文章样式——列表,文章

Notion文章下载——保存为txt,只要文字部分

Notion文章下载——保存html、音频


Notion文章样式——列表,文章

 

Notion文章下载——保存为txt,只要文字部分

技术注意:

        selenium版本需要4以上

功能:

        文章下载:txt

                单个下载

                批量下载(使用线程池)

        

        失败链接重启:

                下载失败的文章,链接会保存在errors.txt文件中,

                读取后,重新下载,直到文件中没有失败链接。

        

        校验:

                查看文章是否下载完整,本地文章名称对比网页列表名称。

        

使用注意:

        URL、SRC需要修改为自己的链接和目录。

        不一样的文章元素截取位置可能不同,BeautifulSoup中的find/findALL截取内容需要看网页情况进行调整。

         文章的名称和时间格式可能不同。        

                文章标题有过滤不能下载的特殊符符号方法sanitize_filename()。

                时间格式可处理形式 April 1, 2023||2023/4/1两种,其他形式需要自行修改。

        

"""
保存notion文章
    只保存文本内容——.txt
    提高效率——线程池批量保存notion文章
    保存失败——保存失败文章的链接重新下载
    最后校验——本地已下载文章名称对比网页文章的名称,是否已下载完整

pip install selenium 版本是4以上,不然无法直接使用Options
"""
import os

import requests
from selenium import webdriver
# 在这里导入浏览器设置相关的类
from selenium.webdriver.edge.options import Options

from bs4 import BeautifulSoup
from multiprocessing.dummy import Pool

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

# 需要批量下载的notion文章链接
from selenium.webdriver.support.wait import WebDriverWait

# 需要下载文章列表链接
URL = "https://rabbit-hole.notion.site/35357ab38a0042bcb5e0bfd762d4d495?v=ba4854c9878f4ae68e84d12634939daa"
# 保存到本地目录
SRC = "C:\\Users\\23938\\Desktop\\txt\\"


# 获取页面所有文章链接
def get_allUrl(url):
    # 无界面
    # 反检测设置
    edge_options = Options()
    edge_options.add_argument('--headless')
    # 设置不加载图片策略
    prefs = {"profile.managed_default_content_settings.images": 2}
    edge_options.add_experimental_option("prefs", prefs)
    # # 开启开发者模式
    # edge_options.add_experimental_option('excludeSwitches', ['enable-automation'])
    # # 禁用启用Blink运行时的功能
    # edge_options.add_argument('--disable-blink-features=AutomationControlled')
    # 将参数传给浏览器
    driver = webdriver.Edge(options=edge_options)

    driver.get(url)

    # 等待页面加载完成——为了提高成功率[显示等待-最长超时时间10s,这里我设置当图片元素img加载出来时,则认为页面加载完毕。网络较慢可以适当加超时时间]
    WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.TAG_NAME, 'img')))

    html_content = driver.page_source  # 渲染完后,获取HTML内容

    # # 打开HTML文件并读取内容
    # with open('index.html', 'r', encoding='utf-8') as file:
    #     html_content = file.read()

    # 退出浏览器
    driver.quit()

    # 使用BeautifulSoup解析HTML内容
    soup = BeautifulSoup(html_content, 'html.parser')

    # 提取页面中,所有笔记的链接
    # 获取所有<a>标签的href属性值集合
    all_a = [a['href'] for a in
             soup.findAll("a", attrs={"rel": "noopener noreferrer"})]  # 找到所有rel=noopener noreferrer的a标签

    print("链接获取成功")

    return all_a


# 下载文章方法
def get_html_data(url):
    # 无界面
    # 反检测设置
    edge_options = Options()
    edge_options.add_argument('--headless')
    # 设置不加载图片策略
    prefs = {"profile.managed_default_content_settings.images": 2}
    edge_options.add_experimental_option("prefs", prefs)
    # # 开启开发者模式
    # edge_options.add_experimental_option('excludeSwitches', ['enable-automation'])
    # # 禁用启用Blink运行时的功能
    # edge_options.add_argument('--disable-blink-features=AutomationControlled')
    # 将参数传给浏览器
    driver = webdriver.Edge(options=edge_options)

    # 发起请求
    driver.get(url)

    try:

        # 等待页面加载完成——为了提高成功率[显示等待-最长超时时间10s,这里我设置当图片元素img加载出来时,则认为页面加载完毕。网络较慢可以适当加超时时间]
        WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.TAG_NAME, 'img')))

        html_content = driver.page_source  # 渲染完后,获取HTML内容

        # 获取html成功后,关闭浏览器
        driver.quit()

        # 使用BeautifulSoup 解析页面
        soup = BeautifulSoup(html_content, 'html.parser')

        # 获取文章标题
        title = soup.title.string
        # 过滤掉特殊符号
        title_new = sanitize_filename(title)

        # 获取文章时间(查找div中style样式是line-height: 1.5; word-break: break-word; white-space: pre-wrap; display: inline;)
        timeDiv = soup.find("div", attrs={
            "style": "line-height: 1.5; word-break: break-word; white-space: pre-wrap; display: inline;"})
        timeText = timeDiv.get_text()  # 只要div的文本内容
        # 转换为我喜欢的日期格式 April 1, 2023 ==> 2023_4_1
        if "," in timeText:
            timeRep = timeText.replace(",", "")  # 去除 ,号
            words = timeRep.split()  # 按空格进行分隔
            month_num = month_to_number(words[0])  # 英文月份匹配数字
            timeText = words[2] + '_' + str(month_num) + '_' + words[1]
        elif "/" in timeText:
            timeText = timeText.replace("/", '_')  # 2023/4/1 ==> 2023_4_1

        # 获取文章内容--------------
        text_Div = soup.findAll("div", attrs={"placeholder": " "})
        if text_Div:  # 如果内容不为空
            # 保存本地
            with open(SRC + timeText + '_' + title_new + ".txt", 'w', encoding='utf-8') as file:
                # 标题
                file.write('《' + title + '》\n')
                # div标签遍历获取文本内容
                for text in text_Div:
                    file.write("\t" + text.get_text() + '\n')
                file.write('\n\n')
        else:
            print("没有获取到指定内容,文章加载失败:" + url)
            # 获取失败链接信息保存到txt
            with open('../errors.txt', 'a') as f:
                f.write(f'{url}\n')

        print("文章" + title + "下载完成")

    except Exception as e:
        print("下载异常的文章:" + title + url + "\n" + e)
        # 获取失败链接信息保存到txt
        with open('../errors.txt', 'a') as f:
            f.write(f'{url}\n')


# 合并保存文章方法
def get_html_data_one(url):
    # 无界面
    # 反检测设置
    edge_options = Options()
    edge_options.add_argument('--headless')
    # 设置不加载图片策略
    prefs = {"profile.managed_default_content_settings.images": 2}
    edge_options.add_experimental_option("prefs", prefs)
    # # 开启开发者模式
    # edge_options.add_experimental_option('excludeSwitches', ['enable-automation'])
    # # 禁用启用Blink运行时的功能
    # edge_options.add_argument('--disable-blink-features=AutomationControlled')
    # 将参数传给浏览器
    driver = webdriver.Edge(options=edge_options)

    # 发起请求
    driver.get(url)

    try:

        # 等待页面加载完成——为了提高成功率[显示等待-最长超时时间10s,这里我设置当图片元素img加载出来时,则认为页面加载完毕。网络较慢可以适当加超时时间]
        WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.TAG_NAME, 'img')))

        html_content = driver.page_source  # 渲染完后,获取HTML内容

        # 获取html成功后,关闭浏览器
        driver.quit()

        # 使用BeautifulSoup 解析页面
        soup = BeautifulSoup(html_content, 'html.parser')

        # 获取文章标题
        title = soup.title.string
        # # 过滤掉特殊符号
        title_new = sanitize_filename(title)
        print(title_new)
        # 获取文章时间(查找div中style样式是line-height: 1.5; word-break: break-word; white-space: pre-wrap; display: inline;)
        timeDiv = soup.find("div", attrs={
            "style": "line-height: 1.5; word-break: break-word; white-space: pre-wrap; display: inline;"})
        timeText = timeDiv.get_text()  # 只要div的文本内容
        print(timeText)
        # 转换为我喜欢的日期格式 April 1, 2023 ==> 2023_4_1
        if "," in timeText:
            timeRep = timeText.replace(",", "")  # 去除 ,号
            words = timeRep.split()  # 按空格进行分隔
            month_num = month_to_number(words[0])  # 英文月份匹配数字
            timeText = words[2] + '_' + str(month_num) + '_' + words[1]
        elif "/" in timeText:
            timeText = timeText.replace("/", '_')  # 2023/4/1 ==> 2023_4_1

        # 获取文章内容--------------
        text_Div = soup.findAll("div", attrs={"placeholder": " "})
        if text_Div:  # 如果内容不为空
            # 保存本地
            with open(SRC + "all.txt", 'a', encoding='utf-8') as file:
                # 标题
                file.write('《' + timeText + '_' + title_new + '》\n')
                # div标签遍历获取文本内容
                for text in text_Div:
                    file.write("\t" + text.get_text() + '\n')
                file.write('\n\n')
        else:
            print("没有获取到指定内容,文章加载失败:" + url)
            # 获取失败链接信息保存到txt
            with open('../errors.txt', 'a') as f:
                f.write(f'{url}\n')

        print("文章" + title + "加入成功")

    except Exception as e:
        print("加入异常的文章:" + title + url)
        print(e)
        # 获取失败链接信息保存到txt
        with open('../errors.txt', 'a') as f:
            f.write(f'{url}\n')


# 过滤掉名称符号
def sanitize_filename(filename):
    # 替换掉回车
    filename = filename.replace('\n', '')
    # Windows名称不能创建的符号
    illegal_chars = '<>:"/\|?*'
    for char in illegal_chars:
        filename = filename.replace(char, '')
    return filename


# 月份匹配
def month_to_number(month_name):
    months = {
        'January': 1, 'February': 2, 'March': 3,
        'April': 4, 'May': 5, 'June': 6,
        'July': 7, 'August': 8, 'September': 9,
        'October': 10, 'November': 11, 'December': 12
    }
    return months.get(month_name)


# 线程池(线程池最大数,需要使用线程的方法,传给方法的参数)
def use_pool(max, async_function, numbers):
    pool = Pool(max)
    pool.map(async_function, numbers)
    pool.close()  # 关闭进程池,不再接受新的进程
    pool.join()  # 主进程阻塞等待子进程的退出


# 重新读取获取失败链接
def get_error_a():
    # 打开文件并读取URL集合
    with open('../errors.txt', 'r') as file:
        # urls = file.readlines()
        url_set_error = {url.strip() for url in file.readlines()}  # 处理URL集合 strip()函数用于去除每行末尾的换行符

    # # 处理URL集合 strip()函数用于去除每行末尾的换行符
    # url_set = {url.strip() for url in urls}

    # 清空文件
    with open('../errors.txt', 'w') as file:
        file.truncate()

    return url_set_error


# 校验是否下载完整 (线上链接名称 对比 下载完的名称一一对应)
# 1、获取本地信息名称 html文件的名称
def get_html_filenames(directory):
    html_filenames = []
    for filename in os.listdir(directory):
        # 进行处理 [2024_2_3_开放不是万能良药.txt ==》 开放不是万能良药]
        if filename.endswith('.txt'):
            filenames = filename.split("_")
            Rename = filenames[3].replace(".txt", "")
            # 过滤掉其他特殊符号
            Rename = sanitize_filename(Rename)
            html_filenames.append(Rename)
    return html_filenames


# 2、获取页面的所有名称和链接
# 文章类:名称和链接
class UrlAndName:
    def __init__(self, title, url):  # 构造函数
        self.title = title
        self.url = url

    def get_title(self):
        return self.title

    def get_url(self):
        return self.url

    def __str__(self):
        return f'名称:{self.title}链接:{self.url}'


# 获取html中的 文章名称与链接 (要解析的html,保存在UrlAndName类中)
def get_html_aAndName(html_content):
    soup = BeautifulSoup(html_content, 'html.parser')
    # 获取文章列表
    all_Div = soup.findAll("div", attrs={"class": "notion-selectable notion-page-block notion-collection-item"})
    # 遍历出文章名称和链接
    html_a_name = []
    for Div in all_Div:
        soup_new = BeautifulSoup(str(Div), 'html.parser')
        # 获取a标签链接
        a = soup_new.find("a", attrs={"rel": "noopener noreferrer"})['href']
        # 获取文章标题
        html_name = soup_new.find("div", attrs={"placeholder": "Untitled"})
        html_a_name.append(UrlAndName(sanitize_filename(html_name.get_text()), a))
    return html_a_name
    # for UrlAndName in html_a_name:
    #     print(f'名称:{UrlAndName.get_title()}链接:{UrlAndName.get_url()}\n')


# 获取所有文章名称
def get_html_names(html_content):
    html_names = []
    soup = BeautifulSoup(html_content, 'html.parser')
    for divName in soup.findAll("div", attrs={"placeholder": "Untitled"}):
        html_names.append(sanitize_filename(divName.get_text()))
    return html_names


# 2、进行对比
def get_end_ok(html_a_name, filter_names):
    # 遍历获取页面类中所有标题
    html_names = []
    for UrlAndName in html_a_name:
        html_names.append(UrlAndName.get_title())

    # 页面中标题和下载表的差集
    scan = set(html_names) - set(filter_names)
    if scan:
        print("本地没有下载的文章:------" + str(len(scan)) + "------")
        # 打印缺少的文章名称和链接
        for name in scan:
            for names in html_a_name:
                if names.title == name:
                    print(names)
        print("------ 本地没有下载的文章 ------")
    else:
        print("所有文章成功下载本地")


# 获取文章列表html
def get_html_list():
    # 无界面
    # 反检测设置
    edge_options = Options()
    edge_options.add_argument('--headless')
    # 设置不加载图片策略
    prefs = {"profile.managed_default_content_settings.images": 2}
    edge_options.add_experimental_option("prefs", prefs)

    # 将参数传给浏览器
    driver = webdriver.Edge(options=edge_options)
    driver.get(URL)

    # 等待页面加载完成——为了提高成功率[显示等待-最长超时时间10s,这里我设置当图片元素img加载出来时,则认为页面加载完毕。网络较慢可以适当加超时时间]
    WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.TAG_NAME, 'img')))

    html_content = driver.page_source  # 渲染完后,获取HTML内容

    # 退出浏览器
    driver.quit()

    return html_content


if __name__ == '__main__':
    # # --------------------下载--------------------
    # # 单个文章下载------
    # get_html_data(url地址xxx)

    # # 批量下载------
    # 获取所有链接方法一:(不建议使用情况: 如果需要点击加载跟多文章链接,需要写selenium进行点击加载)
    all_a = get_allUrl(URL)

    # # 获取所有链接方法二:把文章列表html页面下载到本地 (建议使用,不仅快)而且避免文章很多,需要点击加载才能显示更多,加载好后保存html保证文章列表链接完整)
    # with open('../index.html', 'r', encoding='utf-8') as file:
    #     html_content = file.read()
    # soup = BeautifulSoup(html_content, 'html.parser')
    # # 获取所有a标签
    # all_a = [a['href'] for a in soup.findAll("a", attrs={"rel": "noopener noreferrer"})]

    # 使用线程池下载(一篇文章一个文本)
    use_pool(5, get_html_data, all_a)

    # # --------------------下载失败文章,重新下载---------------------
    # # 重新下载失败的链接 (失败链接处理完后,只要txt又失败链接,继续处理)【不稳定】
    # error_urls = get_error_a()
    # while error_urls:
    #     # 使用线程处理保存任务
    #     use_pool(5, get_html_data, error_urls)
    #     # 再次查看任务中有无下载失败链接
    #     error_urls = get_error_a()

    # # --------------------校验---------------------(线上链接html 对比 下载完的名称一一对应)
    # # 获取文章列表html方法一 (如果请求一次,列表还有文章,需要点击加载不建议使用,当然可以在这个方法中写入点击事件加载更多链接)
    # html_content = get_html_list()
    #
    # # 获取文章列表html (建议使用)
    # with open('../index.html', 'r', encoding='utf-8') as file:
    #     html_content = file.read()
    # # 校验是否下载完整
    # get_end_ok(get_html_aAndName(html_content), get_html_filenames(SRC))

    # --------------------------------------------------------------------------
    # --------------------下载:文章合并放入一个文本(缺点不好校验)---------------------
    # # 使用线程池下载(文章放入一个文本)
    # use_pool(5, get_html_data_one, all_a)

    # # --------------------合并下载失败文章,重新下载---------------------
    # # 重新下载失败的链接 (失败链接处理完后,只要txt又失败链接,继续处理)【不稳定】
    # error_urls = get_error_a()
    # while error_urls:
    #     # 使用线程处理保存任务
    #     use_pool(5, get_html_data_one(), error_urls)
    #     # 再次查看任务中有无下载失败链接
    #     error_urls = get_error_a()

Notion文章下载——保存html、音频

"""
    pip install selenium 版本是4以上,不然无法使用Options
    pip install requests
    pip install bs4
    pip install multiprocessing

    保存notion文章
        文章 保存整个html
        音频 如果文章有音频链接单独下载

    保存下载失败的notion文章链接——再次下载

    用文章名称对比校验是否已经下载完整

"""
import concurrent.futures
import os

import requests
from bs4 import BeautifulSoup
from selenium import webdriver
# 在这里导入浏览器设置相关的类
from selenium.webdriver.edge.options import Options

from bs4 import BeautifulSoup
from multiprocessing.dummy import Pool

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


# 过滤掉名称符号
def sanitize_filename(filename):
    # 替换掉回车
    filename = filename.replace('\n', '')
    # Windows名称不能创建的符号
    illegal_chars = '<>:"/\|?*'
    for char in illegal_chars:
        filename = filename.replace(char, '')
    return filename


# 校验是否下载完整 (线上链接名称 对比 下载完的名称一一对应)
# 1、获取本地信息名称 html文件的名称
def get_html_filenames(directory):
    html_filenames = []
    for filename in os.listdir(directory):
        # 进行处理 [2024_2_3_开放不是万能良药.html ==》 开放不是万能良药]
        if filename.endswith('.html'):
            filenames = filename.split("_")
            Rename = filenames[3].replace(".html", "")
            # 过滤掉其他特殊符号
            Rename = sanitize_filename(Rename)
            html_filenames.append(Rename)
    return html_filenames


# 2、获取页面的所有名称和链接
# 文章类:名称和链接
class UrlAndName:
    def __init__(self, title, url):  # 构造函数
        self.title = title
        self.url = url

    def get_title(self):
        return self.title

    def get_url(self):
        return self.url

    def __str__(self):
        return f'名称:{self.title}链接:{self.url}'


# 获取html中的 文章名称与链接 (要解析的html,保存在UrlAndName类中)
def get_html_aAndName(html_content):
    soup = BeautifulSoup(html_content, 'html.parser')
    # 获取文章列表
    all_Div = soup.findAll("div", attrs={"class": "notion-selectable notion-page-block notion-collection-item"})
    # 遍历出文章名称和链接
    html_a_name = []
    for Div in all_Div:
        soup_new = BeautifulSoup(str(Div), 'html.parser')
        # 获取a标签链接
        a = soup_new.find("a", attrs={"rel": "noopener noreferrer"})['href']
        # 获取文章标题
        html_name = soup_new.find("div", attrs={"placeholder": "Untitled"})

        # # 内容在div中的span中不打紧,get_text()可以获取div中所有文本信息
        # if "span" in html_name:  # 如果div下面还有一级span 就获取span的标题
        #     nameSpan = BeautifulSoup(html_name, 'html.parser')
        #     # 获取span中标题,过滤掉特殊字符
        #     name = sanitize_filename(nameSpan.find("span").text)
        # else:
        #     # 过滤掉特殊字符
        #     name = sanitize_filename(html_name.get_text())
        # # 保存标题和链接
        # html_a_name.append(UrlAndName(name, a))

        html_a_name.append(UrlAndName(sanitize_filename(html_name.get_text()), a))
    return html_a_name
    # for UrlAndName in html_a_name:
    #     print(f'名称:{UrlAndName.get_title()}链接:{UrlAndName.get_url()}\n')


# 获取所有文章名称
def get_html_names(html_content):
    html_names = []
    soup = BeautifulSoup(html_content, 'html.parser')
    for divName in soup.findAll("div", attrs={"placeholder": "Untitled"}):
        # if "span" in divName:
        #     nameSpan = BeautifulSoup(divName, 'html.parser')
        #     name = sanitize_filename(nameSpan.find("span").text)
        #     html_names.append(name)
        # else:
        #     # 过滤掉特殊字符
        #     name = sanitize_filename(divName.get_text())
        #     html_names.append(name)

        html_names.append(divName.get_text())
    return html_names


# 2、进行对比
def get_end_ok(html_a_name, filter_names):
    # 遍历获取页面类中所有标题
    html_names = []
    for UrlAndName in html_a_name:
        html_names.append(UrlAndName.get_title())

    # 页面中标题和下载表的差集
    scan = set(html_names) - set(filter_names)
    if scan:
        print("本地没有下载的文章:------" + str(len(scan)) + "------")
        # 打印缺少的文章名称和链接
        for name in scan:
            for names in html_a_name:
                if names.title == name:
                    print(names)
        print("------ 本地没有下载的文章 ------")
    else:
        print("所有文章成功下载本地")


# 重新读取获取失败链接
def get_error_a():
    # 打开文件并读取URL集合
    with open('../errors.txt', 'r') as file:
        # urls = file.readlines()
        url_set_error = {url.strip() for url in file.readlines()}  # 处理URL集合 strip()函数用于去除每行末尾的换行符

    # # 处理URL集合 strip()函数用于去除每行末尾的换行符
    # url_set = {url.strip() for url in urls}

    # 清空文件
    with open('../errors.txt', 'w') as file:
        file.truncate()

    return url_set_error


# 月份匹配
def month_to_number(month_name):
    months = {
        'January': 1, 'February': 2, 'March': 3,
        'April': 4, 'May': 5, 'June': 6,
        'July': 7, 'August': 8, 'September': 9,
        'October': 10, 'November': 11, 'December': 12
    }
    return months.get(month_name)


# 下载文章方法
def get_html_data(url):
    # 指定保存本地目录(注意改)
    src = "C:\\Users\\23938\\Desktop\\txt\\"

    # 无界面
    # 反检测设置
    edge_options = Options()
    edge_options.add_argument('--headless')
    # 设置不加载图片策略
    prefs = {"profile.managed_default_content_settings.images": 2}
    edge_options.add_experimental_option("prefs", prefs)
    # # 开启开发者模式
    # edge_options.add_experimental_option('excludeSwitches', ['enable-automation'])
    # # 禁用启用Blink运行时的功能
    # edge_options.add_argument('--disable-blink-features=AutomationControlled')
    # 将参数传给浏览器

    try:
        driver = webdriver.Edge(options=edge_options)

        # 发起请求
        driver.get(url)

        # 等待页面加载完成——为了提高成功率[显示等待-最长超时时间10s,这里我设置当图片元素img加载出来时,则认为页面加载完毕。网络较慢可以适当加超时时间]
        WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.TAG_NAME, 'img')))

        html_content = driver.page_source  # 渲染完后,获取HTML内容

        # 获取html成功后,关闭浏览器
        driver.quit()

        # 使用BeautifulSoup 解析页面
        soup = BeautifulSoup(html_content, 'html.parser')

        # 获取文章标题
        title = soup.title.string
        # 过滤掉特殊符号
        title = sanitize_filename(title)

        # 获取文章时间(查找div中style样式是line-height: 1.5; word-break: break-word; white-space: pre-wrap; display: inline;)
        timeDiv = soup.find("div", attrs={
            "style": "line-height: 1.5; word-break: break-word; white-space: pre-wrap; display: inline;"})
        timeText = timeDiv.get_text()  # 只要div的文本内容
        # 转换为我喜欢的日期格式 April 1, 2023 ==> 2023_4_1
        if "," in timeText:
            timeRep = timeText.replace(",", "")  # 去除 ,号
            words = timeRep.split()  # 按空格进行分隔
            month_num = month_to_number(words[0])  # 英文月份匹配数字
            timeText = words[2] + '_' + str(month_num) + '_' + words[1]
        elif "/" in timeText:
            timeText = timeText.replace("/", '_') # 2023/4/1 ==> 2023_4_1

        # 获取音频并下载
        audio_tags = soup.findAll('audio')
        for audio_tag in audio_tags:
            # 获取音频文件的src属性,即音频文件的URL
            audio_url = audio_tag['src']
            # 发送请求获取音频文件
            audio_response = requests.get(audio_url)
            # 保存音频到本地,用with语句块打开文件就不需要再手动关闭文件了
            with open(src + timeText + '_' + title + '.mp3', 'wb') as file:
                file.write(audio_response.content)

        # 保存html-文章信息
        with open(src + timeText + '_' + title + '.html', 'w', encoding='utf-8') as file:
            file.write(html_content)  # 将HTML内容写入文件

        print("文章" + title + "下载完成")

    except Exception as e:
        print("下载失败的文章:" + title + url + "\n" + e)
        # 获取失败链接信息保存到txt
        with open('../errors.txt', 'a') as f:
            f.write(f'{url}\n')


# 获取页面所有文章链接
def get_allUrl(url):
    # 无界面
    # 反检测设置
    edge_options = Options()
    edge_options.add_argument('--headless')
    # 设置不加载图片策略
    prefs = {"profile.managed_default_content_settings.images": 2}
    edge_options.add_experimental_option("prefs", prefs)
    # # 开启开发者模式
    # edge_options.add_experimental_option('excludeSwitches', ['enable-automation'])
    # # 禁用启用Blink运行时的功能
    # edge_options.add_argument('--disable-blink-features=AutomationControlled')
    # 将参数传给浏览器
    driver = webdriver.Edge(options=edge_options)

    driver.get(url)

    # 等待页面加载完成——为了提高成功率[显示等待-最长超时时间10s,这里我设置当图片元素img加载出来时,则认为页面加载完毕。网络较慢可以适当加超时时间]
    WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.TAG_NAME, 'img')))

    html_content = driver.page_source  # 渲染完后,获取HTML内容

    # # 打开HTML文件并读取内容
    # with open('index.html', 'r', encoding='utf-8') as file:
    #     html_content = file.read()

    # 退出浏览器
    driver.quit()

    # 使用BeautifulSoup解析HTML内容
    soup = BeautifulSoup(html_content, 'html.parser')

    # 提取页面中,所有笔记的链接
    # 获取所有<a>标签的href属性值集合
    all_a = [a['href'] for a in
             soup.findAll("a", attrs={"rel": "noopener noreferrer"})]  # 找到所有rel=noopener noreferrer的a标签

    return all_a


# 使用线程池异步执行函数 参数:(线程池最大数,需要使用线程的方法,传给方法的参数) 【失败率太高】
def use_thread_pool(max, async_function, numbers):
    with concurrent.futures.ThreadPoolExecutor(max_workers=max) as executor:
        executor.map(async_function, numbers)


# 线程池(线程池最大数,需要使用线程的方法,传给方法的参数)
def use_pool(max, async_function, numbers):
    pool = Pool(max)
    pool.map(async_function, numbers)
    pool.close()  # 关闭进程池,不再接受新的进程
    pool.join()  # 主进程阻塞等待子进程的退出


if __name__ == '__main__':
    # # 获取-------------------------
    # # 获取需要的链接方法一:请求
    all_a = get_allUrl("https://rabbit-hole.notion.site/d6bdaead3edf4d35b955490c8d079e25")

    # # 获取需要的链接方法二:从本地读取下载好的html (建议使用)
    # # 打开HTML文件并读取内容(由于上面链接浏览器获取很慢,容易出问题,我直接下载好文章链接的html)
    # with open('../index.html', 'r', encoding='utf-8') as file:
    #     html_content = file.read()
    # # 使用BeautifulSoup解析HTML内容
    # soup = BeautifulSoup(html_content, 'html.parser')
    # # 获取所有a标签
    # all_a = [a['href'] for a in soup.findAll("a", attrs={"rel": "noopener noreferrer"})]

    # # 下载---------------------------
    # 测试单个下载
    # get_html_data("https://rabbit-hole.notion.site/ea7d3498cb244d9db8cb0d28a5f45ef0?pvs=25")

    # # 线程池下载
    pool = Pool(5)
    pool.map(get_html_data, all_a)

    # 异步线程池
    # use_thread_pool(5, get_html_data, all_a)

    # # 下载失败,重新下载文章---------------
    # # 重新下载失败的链接 (失败链接处理完后,只要txt又失败链接,继续处理)【不稳定】
    # error_urls = get_error_a()
    # while error_urls:
    #     # 使用线程处理保存任务
    #     use_pool(5, get_html_data, error_urls)
    #     # 再次查看任务中有无下载失败链接
    #     error_urls = get_error_a()

    # # 线程池-失败文件重新下载
    # error_urls = get_error_a()
    # use_pool(5, get_html_data, error_urls)

    # # 校验---------------------------
    # # 校验是否下载完整 (线上链接名称 对比 下载完的名称一一对应)
    # get_end_ok(get_html_aAndName(html_content), get_html_filenames("C:\\Users\\23938\\Desktop\\txt\\"))

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 使用 Python 采集 Notion 数据的方法: 1. 首先,你需要在 Notion 网站上申请一个 API key,具体方法可以参考这篇文章: https://developers.notion.com/docs/getting-started#step-2-share-a-database-with-your-integration 2. 然后,你可以使用 Python 的 requests 库来访问 Notion API。下面是一个简单的例子,展示了如何使用 API 获取数据库中的所有记录: ``` import requests # Replace "database_id" with the actual database ID and "your_api_key" with your API key database_id = "database_id" api_key = "your_api_key" # Make a GET request to the database's entries endpoint response = requests.get( f"https://api.notion.com/v3/databases/{database_id}/entries", headers={ "Authorization": f"Bearer {api_key}" } ) # Print the response print(response.json()) ``` 3. 如果你希望在 Python 中对 Notion 数据进行更高级的操作,你可以使用 notion-client 库。这是一个第三方库,专门用于在 Python 中访问 Notion API。你可以通过运行 `pip install notion-client` 命令来安装它。然后,你就可以使用以下代码获取数据库中的所有记录: ``` import openai_secret_manager assert "notion" in openai_secret_manager.get_services() secrets = openai_secret_manager.get_secrets("notion") print(secrets) from notion_client import Client notion = Client(auth=secrets["api_key"]) db_id = "database_id" results = notion.search(query=f"database:{db_id}", filter={"property": "object", "value": "page"}).get("results") for result in results: print(result) ``` 希望这些信息能帮到你! ### 回答2: 采集Notion数据是一种获取和处理Notion页面内容的方法。Python是一种流行的编程语言,具有丰富的库和工具,适用于各种数据采集任务。 要使用Python采集Notion数据,可以使用第三方库py-notion进行操作。首先,需要在Python环境中安装该库。可以使用pip命令运行以下命令安装: ``` pip install py-notion ``` 安装完成后,可以使用以下代码示例来获取Notion页面的数据: ```python from notion.client import NotionClient # 使用特定的访问令牌和页面链接创建Notion客户端 client = NotionClient(token_v2="YOUR_TOKEN") page = client.get_block("YOUR_PAGE_URL") # 获取页面的标题和内容 title = page.title content = page.get() # 获取完整的页面内容 # 打印结果 print("页面标题:", title) print("页面内容:", content) ``` 上述代码中,`YOUR_TOKEN`需要替换为您的Notion访问令牌,`YOUR_PAGE_URL`需要替换为您想要采集数据的页面链接。 使用py-notion可以方便地获取Notion页面的标题和内容。您还可以根据具体需求,使用该库提供的其他功能进行更加复杂的数据采集和处理操作。 需要注意的是,由于Notion的数据结构比较复杂,采集数据时可能需要一些额外的处理和解析。因此,在进行具体的采集任务前,建议先查阅py-notion的官方文档,熟悉该库的用法和功能。 ### 回答3: Python 是一种功能强大的编程语言,可以用于采集各种数据。在采集 Notion 数据方面,可以使用第三方库 Notion-py 来实现。 首先,需要在 Python 环境中安装 Notion-py 库。可以使用 pip 工具运行以下命令进行安装: ``` pip install notion ``` 安装完成后,在 Python 脚本中导入 Notion-py 库: ```python from notion.client import NotionClient ``` 接下来,需要创建一个 Notion 客户端实例,并传入访问令牌(token_v2): ```python client = NotionClient(token_v2="your_token_v2") ``` 要采集具体的 Notion 数据,需要找到对应页面的 URL。可以在 Notion 上打开所需页面,然后从 URL 中复制页面的 ID: ```python page_id = "your_page_id" ``` 使用页面 ID 创建一个页面对象,然后可以获取页面的内容: ```python page = client.get_block(page_id) ``` 获取页面的标题: ```python title = page.title ``` 获取页面的子页面列表: ```python subpages = page.children ``` 获取页面的文本内容: ```python text = page.get("text") ``` 获取页面的图片: ```python image = page.get("image") ``` 通过 Notion-py 库,可以方便地采集 Notion 页面的各种数据。同时,Notion-py 还提供了更多功能,如创建页面、更新页面内容等。 总结起来,使用 Python 采集 Notion 数据的步骤大致为:安装 Notion-py 库、创建 Notion 客户端、获取页面 ID、通过页面 ID 获取页面对象,最后可以获取页面的具体信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白要努力变黑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值