ChatGPT+Google Colab批量抓取NBER工作论文(0基础+代码+Prompt)

如何解决 ChatGPT 在科研学术写作中“不说人话”? 短视频真正改变的,是知识抵达人的方式。真正该改的是信息顺序:先给结论,再讲原因和证据,最后补充必要的边界,边界在这里是护栏,不该挡在正文前面。读者还没质疑,例外和边界已经先摆好了,不敢把话说透,真正好的文章会先把核心判断稳稳立住,再补充复杂性,不会让读者猜半天你到底想说什么。观点还没展开,就先回应并不存在的反对意见,大量篇幅都在证明我没这么说,不过度防御的文章都是前者忙着管理风险,后者才是在推进认识。逐句查看文章中的转折、退让和补充说明,追问一句,如果拿掉这句话,事实是否仍然准确,推理是否依然成立。 阅读详情

img

作者: 张家星
邮箱: zhangjx@stu.zuel.edu.cn

本推文提供:

  • 批量抓取NBER工作论文信息的Python代码
  • 获得正确代码的ChatGPT Prompt过程
  • 本文适用于完全不会爬虫的新手
    • 无需下载Python
    • 手动更改0行代码
    • 云端迅速得到结果
  • 抛砖引玉,欢迎讨论!

【本文内容较多,可以参照目录选择性阅读】

目录:

  • \1. 目的
  • \2. 工具
    • 2.1 ChatGPT
    • 2.2 Google Colab
    • 2.3 GPT+Colab
  • \3. 代码
    • 3.1完整代码
    • 3.2代码详解
  • \4. Prompt 全过程
  • 写在后面

1. 目的

NBER Working Paper是由美国国家经济研究局(NBER)发布的一系列学术论文,旨在分享和讨论经济学领域中的前沿研究成果。

本篇推文的目的是【批量抓取NBER工作论文中的题目、作者、摘要等信息】

未来有待完善之处:

  1. 通过调用开源大模型,抓取后直接翻译为中文,并形成markdown格式文件,方便形成公众号推文。
  2. 同时下载好pdf格式的论文
  3. 只下载本周最新的论文
  4. 进一步研究Google Colab平台

2. 工具

2.1 ChatGPT

前段时间是 ChatGPT 发布两周年,相信大家对它已经十分熟悉,因此这里不再赘述。

2.2 Google Colab

Google Colab(全称 Google Colaboratory)是由 Google 提供的一种基于云端的 Jupyter Notebook 环境,允许用户编写和执行 Python 代码。

Colab 提供免费的计算资源(包括 GPU 和 TPU),使得数据科学、机器学习和深度学习等计算密集型任务更加容易进行。它支持直接从 Google Drive 导入和存储文件,方便用户管理数据。

Colab 主要特点包括:

  • 无需配置环境:用户可以直接在浏览器中使用,免去安装和配置的烦恼。
  • 免费的计算资源:提供 GPU 和 TPU 支持,适合需要高性能计算的项目。
  • 云端存储与共享:与 Google Drive 集成,支持文档和项目的轻松共享和协作。
  • 支持 Python 和常见库:内置了大量 Python 库,特别适合数据分析、机器学习等任务。
  • 代码执行与可视化:支持实时执行代码,并将结果以图形、表格等形式直观展示。

2.3 GPT+Colab

本文通过在 ChatGPT 中提问获取爬虫代码,并将其复制到 Colab 中执行。

实际上谷歌浏览器有个ChatGPT for Google Colab插件,感兴趣的可以下载尝试。

3. 代码

先看一下最终得到的文件,4S下载了50篇论文的信息。

img

3.1完整代码

无需配置本地 Python 环境,直接将下面的代码,复制到 Google Colab 的笔记本中,运行代码即可。(截至2024年12月4日13:28:06,亲测可用)

如果想要理解代码逻辑,请看3.2代码详解

img

# python

import requests
from bs4 import BeautifulSoup
import csv
import time
from tqdm import tqdm
import os
import re
import logging
from concurrent.futures import ThreadPoolExecutor, as_completed

# 如果在Google Colab中运行,使用以下模块下载文件
from google.colab import files

# 设置日志配置
logging.basicConfig(filename='nber_scraper.log', level=logging.INFO,
                    format='%(asctime)s:%(levelname)s:%(message)s')

def extract_author_names(authors_html):
    """
    从包含HTML <a> 标签的作者列表中提取纯文本的作者姓名。
    """
    authors = []
    for author_html in authors_html:
        soup = BeautifulSoup(author_html, 'html.parser')
        author_name = soup.get_text(strip=True)
        authors.append(author_name)
    return authors if authors else ['None']

def normalize_punctuation(text):
    """
    将智能标点转换为标准标点。
    """
    # 将智能引号转换为标准引号
    text = re.sub(r'[“”]', '"', text)
    text = re.sub(r"[‘’]", "'", text)
    # 将其他特殊标点转换为标准标点
    text = re.sub(r'–|—', '-', text)
    # 处理其他可能的乱码字符,如"鈥"
    text = text.replace('鈥', '"').replace('鈥', '"').replace('鈥', '"')  # 根据需要添加更多替换规则
    return text

def fetch_nber_working_papers(page=1, per_page=50, sort_by='public_date'):
    """
    从NBER API获取工作论文,并提取标题、作者、发布日期、URL。
    """
    api_url = 'https://www.nber.org/api/v1/working_page_listing/contentType/working_paper/_/_/search'
    params = {
        'page': page,
        'perPage': per_page,
        'sortBy': sort_by
    }

    response = requests.get(api_url, params=params)

    if response.status_code == 200:
        data = response.json()
        papers = data.get('results', [])

        extracted_papers = []

        for paper in papers:
            title = paper.get('title', 'No Title')

            # 提取作者姓名
            authors_html = paper.get('authors', [])
            authors = extract_author_names(authors_html)

            # 使用 displaydate 作为发布日期
            display_date = paper.get('displaydate', 'None')

            # 构建完整的论文URL
            paper_url = f"https://www.nber.org{paper.get('url', '')}"

            extracted_papers.append({
                'title': title,
                'authors': authors,
                'publication_date': display_date,
                'url': paper_url
            })

        return extracted_papers
    else:
        logging.error(f"请求失败,状态码: {response.status_code}")
        return []

def fetch_full_details(paper_url):
    """
    使用requests和BeautifulSoup提取摘要、Working Paper编号和DOI。
    """
    try:
        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'
        }
        response = requests.get(paper_url, headers=headers, timeout=10)
        if response.status_code == 200:
            soup = BeautifulSoup(response.text, 'html.parser')

            # 定位摘要所在的div
            intro_div = soup.find('div', class_='page-header__intro-inner')
            abstract = 'None'
            if intro_div:
                abstract_p = intro_div.find('p')
                if abstract_p:
                    abstract = abstract_p.get_text(separator=' ', strip=True)
                    abstract = normalize_punctuation(abstract)

            # 定位citation信息
            citation_div = soup.find('div', class_='page-header__citation-info')
            working_paper_number = 'None'
            doi = 'None'
            if citation_div:
                citation_items = citation_div.find_all('div', class_='page-header__citation-item')
                for item in citation_items:
                    label = item.find('span', class_='page-header__citation-item-label')
                    if label:
                        label_text = label.get_text(strip=True)
                        if label_text == 'Working Paper':
                            working_paper_number = item.get_text(strip=True).replace('Working Paper', '').strip()
                        elif label_text == 'DOI':
                            doi = item.get_text(strip=True).replace('DOI', '').strip()

            logging.info(f"成功获取论文详细信息: {paper_url}")
            return {
                'abstract': abstract,
                'working_paper_number': working_paper_number,
                'doi': doi
            }

        else:
            logging.error(f"无法访问论文页面,状态码: {response.status_code},URL: {paper_url}")
            return {'abstract': 'None', 'working_paper_number': 'None', 'doi': 'None'}
    except Exception as e:
        logging.error(f"在获取详细信息时发生错误: {e},URL: {paper_url}")
        return {'abstract': 'None', 'working_paper_number': 'None', 'doi': 'None'}

def fetch_all_details_concurrently(papers):
    """
    使用多线程并发获取所有论文的详细信息。
    """
    with ThreadPoolExecutor(max_workers=10) as executor:
        futures = {executor.submit(fetch_full_details, paper['url']): paper for paper in papers}
        for future in tqdm(as_completed(futures), total=len(futures), desc="并发获取详细信息"):
            paper = futures[future]
            try:
                details = future.result()
                paper['abstract'] = details['abstract']
                paper['working_paper_number'] = details['working_paper_number']
                paper['doi'] = details['doi']
            except Exception as e:
                logging.error(f"在获取论文详细信息时出错: {e},URL: {paper['url']}")
                paper['abstract'] = 'None'
                paper['working_paper_number'] = 'None'
                paper['doi'] = 'None'

def save_to_csv(papers, filename='nber_working_papers_full.csv'):
    """
    将提取的论文信息保存到CSV文件中,并在Google Colab中下载。
    """
    # 定义CSV列的顺序
    fieldnames = ['Working Paper Number', 'Publication Date', 'Title', 'Authors', 'Full Abstract', 'DOI', 'URL']

    # 定义保存路径为 /content 目录(Google Colab环境)
    save_path = os.path.join('/content', filename)

    print(f"准备保存 {len(papers)} 篇论文到 CSV 文件: {save_path}")

    with open(save_path, mode='w', encoding='utf-8-sig', newline='') as file:
        writer = csv.DictWriter(file, fieldnames=fieldnames)
        writer.writeheader()
        for paper in papers:
            writer.writerow({
                'Working Paper Number': paper.get('working_paper_number', 'None'),
                'Publication Date': paper['publication_date'],
                'Title': paper['title'],
                'Authors': ', '.join(paper['authors']),
                'Full Abstract': paper.get('abstract', 'None'),
                'DOI': paper.get('doi', 'None'),
                'URL': paper['url']
            })
            # 可选:打印已保存的论文标题
            print(f"已保存论文: {paper['title']}")

    print(f"数据已保存到 {save_path}")

    # 在Google Colab中下载文件
    try:
        files.download(save_path)
        print(f"文件 {filename} 已下载到本地。")
    except Exception as e:
        print(f"下载文件时出错: {e}")

def main():
    # 打印当前工作目录
    print(f"当前工作目录: {os.getcwd()}")

    # 设置要获取的页数和每页的论文数量
    total_pages = 1  # 示例:获取第一页
    per_page = 50

    all_papers = []

    for page in range(1, total_pages + 1):
        print(f"获取第 {page} 页的论文信息...")
        papers = fetch_nber_working_papers(page=page, per_page=per_page, sort_by='public_date')
        all_papers.extend(papers)
        time.sleep(1)  # 为了避免过于频繁的请求,暂停1秒

    print(f"共获取到 {len(all_papers)} 篇论文的信息。")

    # 使用多线程并发获取详细信息
    print("开始并发获取每篇论文的详细信息...")
    fetch_all_details_concurrently(all_papers)

    # 保存到CSV文件并下载
    save_to_csv(all_papers)

if __name__ == "__main__":
    main()

3.2代码详解

本节根据ChatGPT o1-preview 的回答,提供全部代码解释。

1. 导入必要的模块

# python
import requests
from bs4 import BeautifulSoup
import csv
import time
from tqdm import tqdm
import os
import re
import logging
from concurrent.futures import ThreadPoolExecutor, as_completed  # 修改导入语句

# 如果在Google Colab中运行,使用以下模块下载文件
from google.colab import files

模块解释:

  • requests:用于发送HTTP请求,从NBER API和论文网页获取数据。
  • BeautifulSoup (bs4):用于解析HTML内容,从网页中提取所需的信息。
  • csv:用于将提取的数据写入CSV文件。
  • time:用于控制请求之间的延时,防止过于频繁的请求。
  • tqdm:用于显示进度条,跟踪长时间运行的操作的进度。
  • os:用于处理文件路径和操作系统相关的功能。
  • re:用于正则表达式操作,处理文本中的特殊字符。
  • logging:用于记录脚本运行过程中的信息、错误和警告,便于调试和维护。
  • concurrent.futures.ThreadPoolExecutor, as_completed:用于实现多线程并发请求,提高数据抓取的效率。
  • google.colab.files:专门用于在Google Colab环境中下载生成的文件到本地计算机。

2. 设置日志配置

# 设置日志配置
logging.basicConfig(filename='nber_scraper.log', level=logging.INFO,
                    format='%(asctime)s:%(levelname)s:%(message)s')

**目的:**记录脚本运行过程中发生的事件和错误,便于后续分析和调试。

  • logging.basicConfig:配置日志记录的基本设置。
    • filename='nber_scraper.log':将日志信息写入名为nber_scraper.log的文件中。
    • level=logging.INFO:设置日志级别为INFO,记录INFO及以上级别的信息(如WARNING、ERROR等)。
    • format='%(asctime)s:%(levelname)s:%(message)s':定义日志信息的格式,包括时间戳、日志级别和消息内容。

3. 定义函数:extract_author_names

def extract_author_names(authors_html):
    """
    从包含HTML <a> 标签的作者列表中提取纯文本的作者姓名。
    """
    authors = []
    for author_html in authors_html:
        soup = BeautifulSoup(author_html, 'html.parser')
        author_name = soup.get_text(strip=True)
        authors.append(author_name)
    return authors if authors else ['None']

目的:将HTML格式的作者信息转换为纯文本,便于后续处理和保存。

  • 输入参数:authors_html,包含多个HTML 标签的作者信息。
  • 遍历每个作者的HTML片段。
  • 使用BeautifulSoup解析HTML,提取纯文本的作者姓名。
  • 将提取的作者姓名添加到authors列表中。
  • 返回值:返回包含所有作者姓名的列表;如果没有作者信息,则返回[‘None’]。

4. 定义函数:normalize_punctuation

def normalize_punctuation(text):
    """
    将智能标点转换为标准标点。
    """
    # 将智能引号转换为标准引号
    text = re.sub(r'[“”]', '"', text)
    text = re.sub(r"[‘’]", "'", text)
    # 将其他特殊标点转换为标准标点
    text = re.sub(r'–|—', '-', text)
    # 处理其他可能的乱码字符,如"鈥"
    text = text.replace('鈥', '"').replace('鈥', '"').replace('鈥', '"')  # 根据需要添加更多替换规则
    return text

目的: 确保文本中的标点符号统一,避免在保存到CSV或显示时出现乱码问题。

  • 输入参数:text,包含可能的智能标点或乱码字符的文本。

5. 定义函数:fetch_nber_working_papers

def fetch_nber_working_papers(page=1, per_page=50, sort_by='public_date'):
    """
    从NBER API获取工作论文,并提取标题、作者、发布日期、URL。
    """
    api_url = 'https://www.nber.org/api/v1/working_page_listing/contentType/working_paper/_/_/search'
    params = {
        'page': page,
        'perPage': per_page,
        'sortBy': sort_by
    }

    response = requests.get(api_url, params=params)

    if response.status_code == 200:
        data = response.json()
        papers = data.get('results', [])

        extracted_papers = []

        for paper in papers:
            title = paper.get('title', 'No Title')

            # 提取作者姓名
            authors_html = paper.get('authors', [])
            authors = extract_author_names(authors_html)

            # 使用 displaydate 作为发布日期
            display_date = paper.get('displaydate', 'None')

            # 构建完整的论文URL
            paper_url = f"https://www.nber.org{paper.get('url', '')}"

            extracted_papers.append({
                'title': title,
                'authors': authors,
                'publication_date': display_date,
                'url': paper_url
            })

        return extracted_papers
    else:
        logging.error(f"请求失败,状态码: {response.status_code}")
        return []

目的: 通过NBER的API获取工作论文的基本信息,为后续提取更详细的信息(如摘要、DOI等)做准备。

  • 输入参数:
    • page:要获取的页面编号,默认为1。
    • per_page:每页显示的论文数量,默认为50。
    • sort_by:排序方式,默认为按public_date(发布日期)排序。
  • 构建API请求:
    • api_url:NBER API的URL,用于获取工作论文列表。
    • params:请求参数,包括页面编号、每页数量和排序方式。
  • 发送HTTP GET请求:
    • 使用requests.get发送请求,传递URL和参数。
  • 处理响应:
    • 如果响应状态码为200(成功),则解析JSON响应。
    • 从JSON数据中提取results,即论文列表。
  • 提取所需信息:
    • 遍历每篇论文,提取标题、作者、发布日期和URL。
    • 使用extract_author_names函数提取作者姓名。
    • 构建完整的论文URL(因为API返回的URL可能是相对路径)。
    • 将提取的信息添加到extracted_papers列表中。
  • 返回结果:
    • 返回包含所有提取论文信息的列表。
    • 如果请求失败,记录错误并返回空列表。

6. 定义函数:fetch_full_details

def fetch_full_details(paper_url):
    """
    使用requests和BeautifulSoup提取摘要、Working Paper编号和DOI。
    """
    try:
        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'
        }
        response = requests.get(paper_url, headers=headers, timeout=10)
        if response.status_code == 200:
            soup = BeautifulSoup(response.text, 'html.parser')

            # 定位摘要所在的div
            intro_div = soup.find('div', class_='page-header__intro-inner')
            abstract = 'None'
            if intro_div:
                abstract_p = intro_div.find('p')
                if abstract_p:
                    abstract = abstract_p.get_text(separator=' ', strip=True)
                    abstract = normalize_punctuation(abstract)

            # 定位citation信息
            citation_div = soup.find('div', class_='page-header__citation-info')
            working_paper_number = 'None'
            doi = 'None'
            if citation_div:
                citation_items = citation_div.find_all('div', class_='page-header__citation-item')
                for item in citation_items:
                    label = item.find('span', class_='page-header__citation-item-label')
                    if label:
                        label_text = label.get_text(strip=True)
                        if label_text == 'Working Paper':
                            working_paper_number = item.get_text(strip=True).replace('Working Paper', '').strip()
                        elif label_text == 'DOI':
                            doi = item.get_text(strip=True).replace('DOI', '').strip()

            logging.info(f"成功获取论文详细信息: {paper_url}")
            return {
                'abstract': abstract,
                'working_paper_number': working_paper_number,
                'doi': doi
            }

        else:
            logging.error(f"无法访问论文页面,状态码: {response.status_code},URL: {paper_url}")
            return {'abstract': 'None', 'working_paper_number': 'None', 'doi': 'None'}
    except Exception as e:
        logging.error(f"在获取详细信息时发生错误: {e},URL: {paper_url}")
        return {'abstract': 'None', 'working_paper_number': 'None', 'doi': 'None'}

目的: 从每篇论文的详细页面中提取更具体的信息(摘要、工作论文编号、DOI),补充之前通过API获取的基本信息

  • 输入参数:paper_url,单篇论文的详细页面URL。

  • 功能:

  • 发送HTTP GET请求:

    • 使用requests.get发送请求,附带自定义的User-Agent头,以模拟真实的浏览器请求,避免被网站拒绝。
    • 设置timeout=10,即请求超时时间为10秒,防止长时间等待。
  • 处理响应:

    • 如果响应状态码为200(成功),则解析HTML内容。
  • 提取摘要:

    • 使用BeautifulSoup查找包含摘要的``,其类名为page-header__intro-inner。
    • 在该内找到标签,提取文本内容。
    • 使用normalize_punctuation函数标准化标点符号,避免乱码。
  • 提取工作论文编号和DOI:

    • Working Paper:提取工作论文编号。

    • DOI:提取DOI号。

    • 查找包含引用信息的``,类名为page-header__citation-info。

    • 在该内找到所有子,类名为page-header__citation-item。

    • 遍历每个子,根据标签(的文本)确定提取内容:

  • 记录日志:

    • 成功提取后,记录成功信息。
    • 如果请求失败或解析错误,记录错误信息。
  • 返回结果:

    • 返回包含摘要、工作论文编号和DOI的字典。
    • 如果提取失败,返回默认值’None’。

7. 定义函数:fetch_all_details_concurrently

def fetch_all_details_concurrently(papers):
    """
    使用多线程并发获取所有论文的详细信息。
    """
    with ThreadPoolExecutor(max_workers=10) as executor:
        futures = {executor.submit(fetch_full_details, paper['url']): paper for paper in papers}
        for future in tqdm(as_completed(futures), total=len(futures), desc="并发获取详细信息"):
            paper = futures[future]
            try:
                details = future.result()
                paper['abstract'] = details['abstract']
                paper['working_paper_number'] = details['working_paper_number']
                paper['doi'] = details['doi']
            except Exception as e:
                logging.error(f"在获取论文详细信息时出错: {e},URL: {paper['url']}")
                paper['abstract'] = 'None'
                paper['working_paper_number'] = 'None'
                paper['doi'] = 'None'

目的: 并发地提取所有论文的详细信息,显著提升抓取效率。

  • 输入参数:papers,包含基本信息的论文列表,每篇论文是一个字典,包含标题、作者、发布日期和URL。
  • 功能:
  • 创建线程池:
    • 使用ThreadPoolExecutor创建一个包含10个线程的线程池,max_workers=10。
    • 原因:多线程允许同时发送多个HTTP请求,提高数据抓取的效率,显著减少总运行时间。
  • 提交任务:
    • 遍历每篇论文,使用executor.submit提交fetch_full_details函数的任务,传入论文的URL。
    • 创建一个字典futures,键为未来(future)对象,值为对应的论文字典。
  • 处理完成的任务:
    • 使用tqdm和as_completed函数,遍历已完成的未来对象,显示进度条。
    • 对于每个已完成的任务:
    • 获取对应的论文字典。
    • 调用future.result()获取提取的详细信息。
    • 更新论文字典,添加摘要、工作论文编号和DOI。
    • 错误处理:如果在获取详细信息时发生异常,记录错误并将相关字段设为None。

8. 定义函数:save_to_csv

def save_to_csv(papers, filename='nber_working_papers_full.csv'):
    """
    将提取的论文信息保存到CSV文件中,并在Google Colab中下载。
    """
    # 定义CSV列的顺序
    fieldnames = ['Working Paper Number', 'Publication Date', 'Title', 'Authors', 'Full Abstract', 'DOI', 'URL']

    # 定义保存路径为 /content 目录(Google Colab环境)
    save_path = os.path.join('/content', filename)

    print(f"准备保存 {len(papers)} 篇论文到 CSV 文件: {save_path}")

    with open(save_path, mode='w', encoding='utf-8-sig', newline='') as file:
        writer = csv.DictWriter(file, fieldnames=fieldnames)
        writer.writeheader()
        for paper in papers:
            writer.writerow({
                'Working Paper Number': paper.get('working_paper_number', 'None'),
                'Publication Date': paper['publication_date'],
                'Title': paper['title'],
                'Authors': ', '.join(paper['authors']),
                'Full Abstract': paper.get('abstract', 'None'),
                'DOI': paper.get('doi', 'None'),
                'URL': paper['url']
            })
            # 可选:打印已保存的论文标题
            print(f"已保存论文: {paper['title']}")

    print(f"数据已保存到 {save_path}")

    # 在Google Colab中下载文件
    try:
        files.download(save_path)
        print(f"文件 {filename} 已下载到本地。")
    except Exception as e:
        print(f"下载文件时出错: {e}")

目的: 将所有提取的论文信息按照指定的列顺序保存到CSV文件中,并在Google Colab环境中自动下载该文件,便于后续分析和使用。

  • 输入参数:

    • papers:包含所有论文信息的列表,每篇论文是一个字典。
    • filename:保存的CSV文件名,默认为nber_working_papers_full.csv。
  • 功能:

  • 定义CSV列的顺序:

    • Working Paper Number

    • Publication Date

    • Title

    • Authors

    • Full Abstract

    • DOI

    • URL

    • fieldnames列表按照用户指定的顺序排列:

  • 构建保存路径:

    • 使用os.path.join将目录/content与文件名组合,形成完整的保存路径save_path。
    • 注意:/content是Google Colab的默认工作目录。
  • 打开CSV文件:

    • 使用open函数以写模式('w')打开文件,指定编码为utf-8-sig:
    • utf-8-sig:在文件开头添加BOM(字节顺序标记),有助于某些软件(如Excel)正确识别UTF-8编码。
    • newline='':避免在写入CSV时出现多余的空行。
  • 写入CSV文件:

    • 使用paper.get('field', 'None')获取字段值,如果字段不存在则使用None作为默认值。

    • ', '.join(paper['authors']):将作者列表转换为以逗号分隔的字符串。

    • 创建csv.DictWriter对象,指定列名。

    • 写入表头(header)。

    • 遍历每篇论文,按照fieldnames顺序写入数据:

    • 打印保存信息:每保存一篇论文,打印一条消息,显示已保存的论文标题。

  • 下载CSV文件:

    • 使用google.colab.files.download方法在Google Colab中自动下载生成的CSV文件到本地计算机。
    • 错误处理:如果下载过程中发生错误,打印错误信息。

9. 定义函数:main

def main():
    # 打印当前工作目录
    print(f"当前工作目录: {os.getcwd()}")

    # 设置要获取的页数和每页的论文数量
    total_pages = 2  # 示例:获取第一页
    per_page = 50

    all_papers = []

    for page in range(1, total_pages + 1):
        print(f"获取第 {page} 页的论文信息...")
        papers = fetch_nber_working_papers(page=page, per_page=per_page, sort_by='public_date')
        all_papers.extend(papers)
        time.sleep(1)  # 为了避免过于频繁的请求,暂停1秒

    print(f"共获取到 {len(all_papers)} 篇论文的信息。")

    # 使用多线程并发获取详细信息
    print("开始并发获取每篇论文的详细信息...")
    fetch_all_details_concurrently(all_papers)

    # 保存到CSV文件并下载
    save_to_csv(all_papers)

目的:协调整个抓取流程,从获取基本信息到提取详细信息,再到保存和下载,确保流程高效、有序地完成。

  • 打印当前工作目录:

    • 使用os.getcwd()获取并打印当前的工作目录路径。
    • 目的:确认脚本的运行环境和文件保存位置。
  • 设置抓取参数:

    • total_pages = 2:设置要抓取的页数为2页(示例)。
    • per_page = 50:每页抓取50篇论文。
  • 抓取论文基本信息:

    • 打印当前抓取的页数。

    • 调用fetch_nber_working_papers函数抓取当前页的论文信息。

    • 将抓取到的论文信息添加到all_papers列表中。

    • 使用time.sleep(1)暂停1秒,防止过于频繁的请求导致被目标网站封禁。

    • 初始化空列表all_papers,用于存储所有论文的信息。

    • 使用for循环遍历每一页:

  • 打印抓取结果:

    • 打印总共抓取到的论文数量。
  • 并发获取详细信息:

    • 打印开始并发获取详细信息的消息。
    • 调用fetch_all_details_concurrently函数,使用多线程并发地抓取每篇论文的详细信息(摘要、工作论文编号、DOI)。
  • 保存并下载CSV文件:

    • 调用save_to_csv函数,将所有论文信息保存到CSV文件中,并在Google Colab中自动下载。

10. 主程序入口

if __name__ == "__main__":
    main()
  • 作用:
    • 当脚本作为主程序运行时(而不是被导入为模块),执行main()函数。
    • 这是Python中常见的惯用法,用于定义脚本的入口点,确保在直接运行脚本时执行特定的代码。

4. Prompt 全过程

授人以鱼,不如授人以渔。本节提供得到正确代码的全部 Prompt 过程,仅供参考。

Q1: 帮我爬取https://www.nber.org/papers?page=1&perPage=50&sortBy=public_date 这个网站里面所有文章的题目、作者、摘要等信息,并提供google colab 的代码

第一轮回复(ChatGPT 4o):您可以使用 Python 的 requests 库来获取网页内容,并使用 BeautifulSoup 解析 HTML。……

【我将提供的代码复制到 Google Colab 中,并未得到结果。】

Q2: 不好使呢

第二轮回复(ChatGPT 4o):抱歉,可能是因为页面的结构或者 JavaScript 渲染的问题。NBER 网站可能使用了 JavaScript 动态加载数据,而 requests 和 BeautifulSoup 只能解析静态页面,无法处理这些动态加载的内容。

一种有效的方式是使用 Selenium 来模拟浏览器行为,加载所有的 JavaScript 内容并抓取页面。这里是一个更新的示例,使用 Selenium 来爬取 NBER 网站上的文章信息。……

【但在几轮追问下,我仍然无法使用 Selenium 模拟浏览器抓取数据。】

值得注意的是,为了考验 ChatGPT 的能力,我并没有根据它提供的代码进行手动调整(实际是因为我根本不会),而是直接复制它提供的完整代码,在 Colab 中运行,看其能否提供想要的结果。

于是我选择最新的模型 ChatGPT o1-preview 进行追问。

Q3: https://www.nber.org/papers?page=1&perPage=50&sortBy=public_date 帮我把前5篇文章的题目、作者和摘要提取出来

第X轮回复(o1-preview): 思考持续5秒后,给我提供详细的步骤,包括安装必要的依赖项、配置Selenium并启动浏览器、编写爬虫代码以提取前5篇文章的信息等。

【但在几轮追问下,ChatGPT o1-preview 提供的代码仍然无法运行成功。】

或许是给它提供的信息有限?

Q4: 【此处为NBER的网站的源代码(右键查看网页源代码既可获得)】这是网页的源代码,应该如何爬取呢?

第X轮回复(o1-preview): 要爬取您提供的网页源代码中的数据,您需要了解网页内容是如何加载的。根据您提供的源代码,这个网页(NBER的“Working Papers”页面)可能使用动态加载的数据,例如通过API请求获取内容。这意味着直接从静态HTML中提取数据可能不够有效。因此,以下是一个系统化的步骤指南,帮助您有效地爬取所需的数据。

提供相关代码:步骤 1:了解网页结构和数据加载方式;步骤 2:检查API端点……

注意: 根据实际的API响应结构,您可能需要调整数据提取部分。

有些API端点可能需要身份验证或特定的请求头,请根据需要进行设置。

Q5: 示例:使用 requests 访问API,但是无法得到作者等。标题: FinTech Platforms and Asymmetric Network Effects: Theory and Evidence from Marketplace Lending 作者: None 发布日期: None

第X轮回复(o1-preview): 理解了,您在使用 requests 访问 API 时,虽然能够获取到论文标题,但无法获取到作者和发布日期。这个问题可能出在以下几个方面:

  1. API 响应结构:可能作者和发布日期信息位于 JSON 数据的嵌套字段中,您的代码未能正确解析。
  2. 请求参数:可能需要调整请求参数,以确保 API 返回完整的数据。
  3. 访问权限:某些字段可能需要特定的权限或认证才能访问

步骤 1:检查 API 响应结构(提供相关代码)……

import requests
import json

# 定义API端点
api_url = 'https://www.nber.org/api/v1/working_page_listing/contentType/working_paper/_/_/search'

# 定义请求参数(根据需要调整)
params = {
    'page': 1,
    'perPage': 50,
    'sortBy': 'public_date'
}

# 发送GET请求
response = requests.get(api_url, params=params)

# 检查响应状态
if response.status_code == 200:
    data = response.json()
    # 打印完整的JSON响应,便于检查结构
    print(json.dumps(data, indent=2, ensure_ascii=False))
else:
    print(f"请求失败,状态码: {response.status_code}")

【运行了上述代码后,我将返回的信息,再次发给o1-preview】

第X轮回复(o1-preview): 理解了,您在使用 requests 访问 API 时,虽然能够获取到论文标题,但作者和发布日期仍显示为 None。根据您提供的 JSON 数据,问题可能出在以下几个方面:

  1. 发布日期字段:publisheddate 字段为 null,而实际的发布日期信息存储在 displaydate 字段中。
  2. 作者字段的格式:authors 字段中的作者名称是包含在 HTML 标签中的字符串,直接提取可能导致解析错误或显示为 None。

对此:

  1. 使用 displaydate 字段代替 publisheddate 字段来获取发布日期。
  2. 解析 authors 字段中的 HTML 字符串,以提取纯文本的作者姓名。

以下是一个完整的 Python 示例,展示如何正确提取标题、作者和发布日期:……

【需要注意的是,在NBER的首页仅能看到文章的部分摘要,因此需要点击相应文章,跳转到新的页面,才能够得到全部摘要。】

于是乎……

Q6: 但是在这个页面中摘要是不完全的,需要单击相应的文章跳转到另外一个页面才可以

第X轮回复(o1-preview):

  • 使用API获取基本信息:通过API获取工作论文的基本信息,包括标题、作者、显示日期和论文的URL。
  • 访问每篇论文的单独页面:使用获取的URL访问每篇论文的详细页面。
  • 解析详细页面获取完整摘要:从每个详细页面中提取完整的摘要。
  • 数据存储:将提取的所有信息(标题、作者、发布日期、完整摘要、链接)保存到CSV或其他格式中。 ……

img

Q7: 我想把文件存在C:\Users\Admin\Desktop

【追问几轮后(需要将报错反馈给o1-preview),发现可以将文件下载到本地,但是抓取下来的摘要仍不是全部的。】

Q8: 摘要是需要点击对应文章的URL后,去提取摘要。这是点击其中一篇文章的url后得到的网页源代码【相应源代码】

第X轮回复(o1-preview): 给出了相应代码……

img

【复制到 Colab 中可以成功下载,但是会发现有些标点符号或者西文是乱码的。】

img

Q8: 我输出的文字中会有乱码,我看了下实际是一些标点符号

第X轮回复(o1-preview): 给出了相应代码……

【乱码问题解决,但人总是不满足的。】

Q9: 我还想要:Working Paper 33152 DOI 10.3386/w33152 这样的信息

第X轮回复(o1-preview): 给出了相应代码……

【成功得到想要的信息。】

img

Q10: 我想按照 Working Paper Number、Publication Date、Title Authors Full Abstract DOI URL 的顺序

第X轮回复(o1-preview): 给出了相应代码……

【得到想要的字段排序。】

img

写在后面

NBER 可能并不是很难爬取的网站,但是 ChatGPT o1-preview 和 Google Colab 组合起来的威力,还是让我吃惊的。

我之前没有 Python 爬虫基础(甚至Pyhon的基础语法也不是很熟悉),仅是用 Stata 做过一点简单的爬虫。但是通过不断向 ChatGPT 提问,竟然得到了一个完全不用修改的代码。

Google Colab 提供的在线平台,大大省去了本地配置环境的时间。需要注意的是,Colab 提供的免费算力和储存空间是有限的。不过,一般的项目应该是足以应付的。

技术的壁垒正在大大降低,思想的重要性大大增加。

​

如何学习AI大模型?

作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费】

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

四、AI大模型商业化落地方案

img

作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量。

Bright Data ChatGPT 搜索抓取器(Python) 使用 GitHub 登录,然后 fork 该仓库开始进行更改。本项目提供一个使用 Bright Data Web Scraper API 抓取结果的简易 Python 样板代码。 阅读详情

相关推荐

语音测试(二)音频标注(praat)

通过点击红线下方的圆点进行区域划分,在区域中标注所属的类别。按住Alt+Backspace 键取消蓝色线条。

beishida123的博客 3735

谷歌学术文献信息爬取及文献下载

谷歌学术文献信息爬取及文献下载

眼科住院医一枚,偶尔搞搞赛博朋克 5713

基于ROS下的安卓手机图像和IMU跑ORB-SLAM3

接之前文章继续,手上没有现成的单目+IMU硬件,但是安卓手机几乎人人都有。因此,本文讲下如何用手机跑ORB-SLAM3的Mono和Mono_Inertial。 1. 手机与PC通信 基于ROS下的信息发布和订阅,手机和PC在一个局域网下进行信息(image和IMU)传输。 手机APK参考了github上的2个开源Android_Camera-IMU和android_ros_sensors,基于ros_java生成安卓APP,下载安装任一个APP到安卓手机,界面分别是这样: 手机和PC连一个无

h_372101的博客 1万+

台湾各个大学硕博论文链接,很全,有的可以全文下载。

http://ntur.lib.ntu.edu.tw/台湾大学机构典藏http://etds.ncl.edu.tw/cgi-bin/gs32/gsweb.cgi/ccd=uH.m91/webmge?Geticket=1台湾国家图书馆 全国博硕士论文资讯网http://etd.lib.nctu.edu.tw/cgi-bin/gs32/gsweb.cgi/login?o=dwebmge&amp;cac...

weixin_34010566的博客 4550

保姆级避坑指南:在Ubuntu 18.04上搞定速腾Helios雷达驱动与fast-LIO2的完整配置流程

本文提供了一份详细的速腾Helios雷达与fast-LIO2在Ubuntu 18.04上的配置避坑指南,涵盖驱动安装、数据格式转换到建图全流程。特别针对常见编译错误和数据转换问题提供了解决方案,帮助开发者高效完成环境搭建与建图任务。

weixin_27252001的博客 113

LVGL高效加载外部Flash图片资源的实现与优化

本文深入探讨了在嵌入式UI开发中,如何为LVGL高效加载外部Flash中的图片资源。针对内部Flash容量不足的痛点,详细解析了LVGL的图片处理原理,并对比了内存映射与流式解码两种主流实现方案。文章重点提供了性能优化技巧与实战避坑指南,旨在帮助开发者实现流畅的图片加载体验,解决SPI Flash读取慢、内存占用高等核心挑战。

t1u2v的博客 462

AI在知识管理中的NLP应用解析

本文将探讨人工智能在知识管理领域中的自然语言处理(NLP)应用,重点分析NLP技术如何提升知识检索的效率与准确性。通过实例解析,进一步阐述NLP在信息提取、语义理解和用户交互方面的优势,以及其对企业知识管理系统的影响与潜在价值。

liju_yang的博客 479

python -- 海洋气象科研论文中常用绘图配色汇总

当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。可以通过自定义选取不同颜色的rgb,通过自定义的方式构建colormap。

weixin_68789096的博客 972

零基础也能用ChatGPT写代码,简直不要太爽

ChatGPT作为一个功能强大,用途广泛的聊天机器人,我们能用它写论文,写作业,写歌,写小说,还能写代码,极大提升生产力。

u011876982的博客 7618

【25届数字IC秋招总结】面试经验6——经纬恒润

25届数字ic面试记录——经纬恒润

lalala0635的博客 991

PPT制作能力在职场中真的重要吗?一定要美术功底才能学好PPT吗?

我推出PPT技能培训专栏啦!好的PPT可以让你事半功倍、2023拥有PPT能力还可以让你具备一门极有价值的斜杠能力。更多内容请进:梦幻训练营专栏。专栏内会用本人积累的近10年的PPT学习方法论在短时间内教会你如何制作出精美绝伦的PPT,每篇教程后还会免费赠送一些小福利,不可多得。

打造全国最全的AI Agent开发知识领域的博客 728

零基础如何使用ChatGPT快速学习Python

本解决方案通过ChatGPT提供个性化的Python学习路径,涵盖理论学习、代码实践以及项目开发。核心功能包括:学习计划定制:根据用户水平生成学习计划。实时互动答疑:随时解答学习中的问题。代码生成与优化:提供示例代码并进行优化建议。项目指导:根据用户兴趣生成实践项目并提供指导。相关工具和软件:ChatGPT(免费版或Plus版本)。Anaconda(管理Python环境)。VS Code(安装Python插件)。

AI智能体研究 2042

新凯来嵌入式面经及参考答案

利用编译器预定义宏判断目标架构,如。

大模型大数据攻城狮的专栏 2065

ChatGPT 广告技术栈架构拆解:多轮意图、LLM 工具编排、ANN 召回与拍卖闭环

基于 OpenAI 官方工程文章,拆解 ChatGPT 广告系统如何用有状态会话理解多轮意图,以独立链路隔离自然回答,再由 LLM 编排召回、过滤、相关性评分、拍卖和最终交付,并给出可复用的超时、观测、安全与反馈闭环设计。

jerry764的博客 375

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

ChatGPT Projects 使用教程:项目指令、文件管理与上下文复用

使用ChatGPT的Projects功能可高效处理长期任务,避免重复说明背景与要求。通过设置项目指令、上传参考文件、复用上下文,实现代码分析、文档维护等任务的持续优化。建议按任务类型建项目,配置简洁规则,重要结论存为独立文档,避免依赖记忆遗漏。适用于有固定流程、需多资料协作的场景,但不可替代Git版本管理。

carriedream的博客 289

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

《C++ 项目:手写大模型接入 SDK》ChatGPT接口设计(下):流式响应实现和测试

本文详细实现了ChatGPT ResponsesAPI的流式响应接口,重点解析了SSE半包缓冲处理的必要性及多事件类型(如response.output_text.delta、error等)的差异化处理逻辑。针对200状态码不等于调用成功的坑点,通过content_receiver回调捕获业务异常。基于抽象基类LLMProvider,仅需修改20%适配代码,即可完成新模型接入,验证了SDK架构的高扩展性与可维护性。

2501_91275995的博客 659

ChatGPT、Codex工程实战:数据库迁移脚本开发环境测试通过,为什么生产上线仍可能锁表甚至丢数据?

ChatGPT、Codex生成的数据库迁移脚本开发环境测试通过,为什么生产上线仍可能锁表甚至造成数据不一致?本文从Java订单系统生产变更切入,分析MySQL DDL、元数据锁、大批量数据回填、新旧版本兼容和数据迁移风险,并介绍Expand-Contract分阶段迁移方案。

lb654509656的博客 314

姿势库 / 服装库 / 人像库一键填充到 ChatGPT、Gemini、豆包(无需 API Key,附安装教程)

一个用户脚本,在 ChatGPT、Gemini、Grok、豆包、通义千问、腾讯元宝、Kimi、即梦等页面里嵌入「参考库」面板,把姿势、服装、人像参考图和规范化提示词一键填入对话框。版权说明:脸库 CC0;姿势库、服装库禁止二次分发。脚本不含本地图片,只在运行时读取公开地址。

yjc_1111的专栏 227

ChatGPT Images 2.6 实测解读:一句话直出 GIF,Flare 提速 46%,API 支持 2~64 帧动图

过去两年,AI 生图解决了"画得像不像""字写得对不对"的问题,但交付物始终是一张静态图。想让它动起来,通常要另外找视频模型,或者自己拆帧、用 PS、ffmpeg 合成 GIF——对运营、设计、做表情包的人来说,这一步既麻烦又容易翻车:帧之间画风跳变、角色走样、文件体积失控。这次 OpenAI 发布的,把这一步直接收进了生图本身:在对话里说一句"能做成 GIF 吗",返回的就是一张可循环播放的动图,而且生成后还能接着改。按 OpenAI 的说法,这是第一个原生直出 GIF 的主流生图产品。

JEECG官方博客 227

ChatGPT Images 2.6 入门:保存角色参考图并生成循环 GIF

按官方 Images in ChatGPT 说明,介绍在 ChatGPT 中把照片存成角色参考并用 @名字复用,再用提示词或静图生成循环 GIF、打开后调速并保存分享的完整步骤。

死磕音视频 203

ChatGPT Images 2.6 商业落地与场景应用指南

本文聚焦电商与设计团队的视觉生产痛点,提出“人机协同”的AI高效工作流。通过十大实战场景,系统拆解商品图生成、海报自动化、风格一致性控制、提示词工程等关键环节,构建可复制、可量化的视觉生产管线。强调以标准化模板、模块化提示词与人机协作闭环,实现从构思到成图的极速落地,显著提升效率与质量,助力各行业实现视觉内容的智能化升级。

frt的博客 274

QVeris MCP 连接到 ChatGPT:让 AI 调用专业数据

一个远程地址,完成 OAuth 授权,把 QVeris 接进 ChatGPT。本文整理网页版、桌面端配置,并用 AAPL 报价查询验证连接。

QVeris_Friends的博客 205

在 Claude 中配置与使用图表编辑器MCP,把数据变成图表

ChartchooserMCP是基于ModelContextProtocol的图表生成服务,可将数据直接转化为Highcharts图表或仪表盘,集成于Claude与ChatGPT。通过简单配置,用户在对话中粘贴数据并回答几项问题,即可自动生成生产级图表。支持自然语言调整样式、类型与布局,显著提升可视化效率。关键技巧包括:保持表头清晰、明确分析目标、多指标需求直接请求仪表盘。配置后一次设置,长期复用,大幅降低选图门槛,适合频繁进行数据分析与汇报的用户。

Highcharts可视化图表库中文博客 642

ChatGPT、Codex并发排查:Spring Boot接口没有报错,为什么线程池队列越来越长,最后整批请求超时?

Spring Boot接口没有报错,CPU和数据库连接池也正常,为什么线程池队列却越来越长?本文从订单服务任务积压故障切入,分析无界队列、最大线程数、CallerRunsPolicy、下游阻塞和任务背压机制,并介绍通过Codex辅助定位线程池瓶颈的方法。

2601_96380027的博客 137

ChatGPT Images 2.6 正式支持 GIF 生成:一张图片也能动起来,AI 动图创作时代来了!

从最初的 AI 文本生成,到 AI 图片生成,再到 AI 视频和现在的 GIF 动图创作,AI 正在不断降低内容创作的技术门槛。以前,一个普通人想制作动画,可能需要学习复杂的软件和专业的制作流程。现在,只需要把自己的想法描述清楚,就有机会让 AI 帮你实现。未来的 AI 不仅能够帮我们生成内容,还能够直接帮我们完成更多视觉创作工作。如果你平时也喜欢折腾 AI 工具,不妨试试这个新功能。你可能会发现,原来一张普通的静态图片,也可以玩出这么多花样!

篮球界最会写bug的人;程序猿中打球最菜的人。 601

OpenAI 合并 ChatGPT 的 Chat 与 Work 标签,ChatGPT 与 Codex 共用 token 配额

OpenAI计划合并ChatGPT桌面应用中的Chat与Work标签页,简化用户界面,使从想法探索到任务执行全程在一个界面完成。新体验将支持文件、插件调用,助力生成网站、演示文稿等。Codex仍独立存在,且聊天与Codex将共享token额度,部分用户或需更频繁等待重置。该调整将先面向部分用户测试,后续推广。此举呼应Anthropic此前对Claude功能的整合。

小川搞开发的博客 178
上一篇: Amazon董事吴恩达新书封神!吹爆这份最真实的人工智能求职指南
下一篇: Langchain如何自动执行python代码 | AI应用开发
AI程序猿人
博客等级 码龄3年 6517粉丝 561原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值