admin管理员组

文章数量:1530266

一、开始前的探索

背景是这样:本人没有学过爬虫,目前需要做一项数据录入的任务。基本内容就是,在网站上输入股票代码,点击提示框内出现的公司名称,再根据查询到的结果录入对应的数据。由于这个工作操作具有重复性,并且查询量巨大,于是考虑采用爬虫录入试试。

首先,我什么都不知道的情况下向gpt询问:

我想要写一个程序,帮助我从这个网站:https://esgratingsxgf/#/home
提取股票代码为000001.SZ到301603.SZ的每年的ESG评级信息,并录入到excel表格的相关位置中,请帮助我实现

这是gpt给出的代码:

import requests
from bs4 import BeautifulSoup
from openpyxl import Workbook
# 设置网站URL和股票代码
url = "https://esgratingsxgf/#/home"
stock_codes = ["000001.SZ", "000002.SZ", ..., "301603.SZ"]  # 替换为您的股票代码
# 创建一个新的Excel工作簿
wb = Workbook()
ws = wb.active
# 设置表头行
ws["A1"] = "股票代码"
ws["B1"] = "年份"
ws["C1"] = "ESG评级"
# 循环遍历每个股票代码
for stock_code in stock_codes:
    # 发送GET请求到网站,股票代码作为参数
    params = {"stockCode": stock_code}
    response = requests.get(url, params=params)
    # 使用BeautifulSoup解析HTML内容
    soup = BeautifulSoup(response.content, "html.parser")
    # 查找每年ESG评级信息
    ratings = soup.find_all("div", {"class": "rating-info"})
    for rating in ratings:
        year = rating.find("span", {"class": "year"}).text.strip()
        esg_rating = rating.find("span", {"class": "rating"}).text.strip()
        # 将数据写入Excel工作表
        ws.append([stock_code, year, esg_rating])
# 保存Excel工作簿
wb.save("esg_ratings.xlsx")

但是运行后发现除了创建一个带表头的excel表格什么都无法实现。。

我意识到gpt只是一个基于大数据的语言模型,而不能联网。我给它一个网址,它无法进行访问并直接给我合适的代码。于是我去学习了一下最基本的爬虫的原理,视频在这里,非常简短不到一个小时就能看完→【00-先导课】爆肝两个月!拜托三连了!这绝对是全B站最用心(没有之一)的Python+爬虫公开课程,从入门到(不)入狱 !_哔哩哔哩_bilibili当然如果懒得看也可以看我下面记录的,当然就没有全部都总结了。

二、准备工作

(一)爬虫基础

1. HTTP请求与响应

每当在浏览器里输入一个网址,其实是在发送一个HTTP(超文本传输协议)请求。这个请求会被发送到服务器,服务器响应请求,并将对应的网页内容返回给你的浏览器。这个过程中,最常见的HTTP请求方法包括GET和POST。GET请求一般用于请求数据,而POST请求一般用于提交数据。

2. 使用Python的requests库发送请求

要用Python模拟这个过程,可以使用Python的requests库发送HTTP请求。以下是如何使用它发送一个GET请求的例子:

import requests
# 发送GET请求
response = requests.get('http://example')
# 输出响应的文本
print(response.text)
3. HTML网页结构和常见标签

HTTP响应返回的通常是HTML文档。HTML(超文本标记语言)是用来构建网页的标准标记语言。它由一系列标签组成,常见的标签包括:

  • <html>:整个网页的根元素。
  • <head>:包含文档的元数据,如CSS样式链接和JavaScript脚本链接。
  • <body>:包含所有可见的网页内容,如文本、图片、视频等。
  • <div>:用于流式布局的容器。
  • <a>:定义超链接,用于从一个页面链接到另一个页面。
  • <p>:定义段落。
3. 使用Beautiful Soup 4解析HTML

解析HTML内容,我们会使用Beautiful Soup 4库,这是一个可以从HTML或XML文件中提取数据的Python库。可以用以下方式使用它:

from bs4 import BeautifulSoup
# 使用前面requests获取的HTML内容
soup = BeautifulSoup(response.text, 'html.parser')
# 解析HTML,提取链接
for link in soup.find_all('a'):
    print(link.get('href'))

这个简单的例子展示了Beautiful Soup 4如何提取HTML中的超链接。它可以用来获取任何标签的内容,根据标签的id、类或属性进行搜索等。

4.使用Selenium和Edge WebDriver进行自动化浏览

由于我要爬取数据的网站需要我进行搜索、点击等交互动作,于是需要使用Selenium和WebDriver来进行网页自动化。Selenium可以模拟用户在浏览器中的行为,如点击、滚动、填写表单等。这对于需要与网页进行交互来获取数据的复杂情况特别有用。

  • 下载和安装:
pip install selenium

下载适用于你的浏览器的WebDriver。(我的是Edge浏览器,也可以用Chrome,火狐等)在Microsoft Edge WebDriver官网下载对应版本的WebDriver。下载后,将WebDriver的可执行文件放置在Python脚本所在的目录或者任何系统路径中的一个文件夹里。这样,Selenium就可以在需要时调用它。

  • 编写基本脚本

以下是一个使用Selenium和Edge WebDriver的基础示例,完成启动Edge浏览器,打开一个网页,并获取网页标题的任务:

from selenium import webdriver
# 指定Edge WebDriver的路径
driver_path = 'C:\\path\\to\\your\\webdriver\\msedgedriver.exe'
driver = webdriver.Edge(executable_path=driver_path)
# 打开一个网页
driver.get('http://example')
# 打印网页标题
print(driver.title)
# 关闭浏览器
driver.quit()

好了基础知识就到这了,更多的我也没看了,毕竟今天就爬取个数据,多的以后再学了。

(二)获取HTML内容

其实前面那些不懂也没事(x)只要知道如何获取网页上内容对应的“位置”就好了。

在需要获取的网页上右键,点击“检查”

然后就可以在这个界面中,就可以寻找到你需要的位置的HTML内容了(鼠标移动到哪里,网页上对应的元素会有显示,如果看不懂可以全用鼠标翻一遍)

三、爬取数据

ok,基本需要的知识已经了解了,接下来可以具有针对性的告诉gpt我们需要完成的任务。

(一)第一个prompt——初步编写程序:

prompt:

在这个网页中,我需要每次手动输入股票代码并查询。我在网页源代码中找到我输入的股票代码的位置是<p class="style-module__resultConLeft2-2DVK2">000008.SZ
要寻找的信息是<p class="style-module__resultConRight1-LIcYz">2024年ESG等级</p><p class="style-module__resultConRight2-16WxH">A-
我要得到的即该股票代码对应的评级“A-”。请问该如何爬取股票代码为000001.SZ到301603.SZ的每年的ESG评级信息?若你无法直接实现,请告诉我你需要什么额外信息

 gpt的回复:

根据你提供的网页结构描述,看起来需要通过动态的交互来获取数据,这可能涉及到JavaScript动态加载的内容。在这种情况下,仅使用requestsBeautifulSoup可能不足以获取信息,因为它们无法执行JavaScript。我们可以考虑使用Selenium这个工具,它能够模拟浏览器行为,包括输入股票代码、提交查询以及等待页面加载完毕。

步骤1: 安装Edge WebDriver

  1. 确保你的Edge浏览器是最新版本。
  2. 下载与你的Edge版本对应的Edge WebDriver。你可以在这里下载:Edge WebDriver。
  3. 将下载的WebDriver放在一个方便的位置,例如你的项目目录或者任何一个系统的环境变量PATH包含的目录。

步骤2: 安装Selenium

如果你还没有安装Selenium,可以通过运行以下命令来安装:

pip install selenium

步骤3: 修改脚本以使用Edge

下面是使用Edge WebDriver的修改后的脚本。你需要替换webdriver路径和对应的CSS选择器,以适应你的具体需求:

from selenium import webdriver
from selenium.webdrivermon.keys import Keys
from selenium.webdriver.edge.service import Service
from openpyxl import Workbook
import time

# 初始化Edge webdriver
s = Service('[你的MicrosoftWebDriver.exe路径]')  # 替换为你的Edge WebDriver路径
driver = webdriver.Edge(service=s)
driver.get('https://esgratingsxgf/#/home')

# 创建Excel文件用于保存数据
wb = Workbook()
ws = wb.active
ws.append(['股票代码', '年份', 'ESG评级'])

# 股票代码范围
stock_codes = ["000001.SZ", "000002.SZ", ..., "301603.SZ"]  # 替换为你的股票代码范围
for code in stock_codes:
    # 查找输入框并输入股票代码
    input_element = driver.find_element_by_css_selector('[输入框的CSS选择器]')
    input_element.clear()  # 清除输入框
    input_element.send_keys(code)  # 输入股票代码
    input_element.send_keys(Keys.RETURN)  # 按Enter键提交查询
    # 等待页面加载(需要根据实际情况调整等待时间)
    time.sleep(3)
    # 解析页面获取ESG评级信息
    try:
        esg_info = driver.find_element_by_css_selector('[结果的CSS选择器]').text.split('年ESG等级')
        year = esg_info[0]
        rating = esg_info[1].strip()
        ws.append([code, year, rating])
    except Exception as e:
        print(f"Error retrieving data for {code}: {str(e)}")
        continue
# 保存Excel文件
wb.save("ESG_Ratings.xlsx")
driver.quit()

在此脚本中,请确保替换:

  • [你的MicrosoftWebDriver.exe路径]:指向你的Edge WebDriver的完整路径。
  • [输入框的CSS选择器][结果的CSS选择器]:基于你观察到的网页源代码,用正确的CSS选择器替换这些占位符。

 (二)第二个prompt——输入特定的css信息:

我发现它没有给我自动填入html内容啊,对于我这种傻子,自己填还是不保险。于是继续问:

我不知道css是什么,但是复制输入框的元素出来的是这些:

<input class="ant-input ant-input-borderless style-module__inputInpu-1Mctk" type="text" placeholder="请输入企业名称或股票代码" value="康佳集团股份有限公司----000016.SZ" data-listener-added_d09b87d0="true">
并且,其中“康佳集团股份有限公司----000016.SZ”是我输入股票代码“000016.SZ”出来的信息,即输入的内容。

 gpt回复:

了解了!CSS选择器是用于在HTML文档中定位和选择特定元素的一种方式,它可以根据元素的类名、ID、属性等进行选择。在你的例子中,我们可以使用类名作为CSS选择器来定位输入框。

定位输入框

根据你提供的输入框的HTML元素:

<input class="ant-input ant-input-borderless style-module__inputInpu-1Mctk" type="text" placeholder="请输入企业名称或股票代码" value="康佳集团股份有限公司----000016.SZ" data-listener-added_d09b87d0="true">

prompt:

这个是复制结果元素得到的信息:

<p class="style-module__resultConRight2-16WxH">A⁻</p> 我需要的是其中的“A-"

  gpt回复:

谢谢你提供结果元素的详细信息!根据这个信息,我们可以使用类名 style-module__resultConRight2-16WxH 来定位包含ESG评级的元素。这个类名看起来是特定的,应该可以用来精确获取每个查询结果的评级信息。

修改后的Selenium脚本

from selenium import webdriver
from selenium.webdrivermon.keys import Keys
from selenium.webdrivermon.by import By  # 导入By类
from selenium.webdriver.edge.service import Service
from openpyxl import Workbook
import time

# 初始化Edge webdriver
s = Service('[你的MicrosoftWebDriver.exe路径]')  # 替换为你的Edge WebDriver路径
driver = webdriver.Edge(service=s)
driver.get('https://esgratingsxgf/#/home')

# 创建Excel文件用于保存数据
wb = Workbook()
ws = wb.active
ws.append(['股票代码', 'ESG评级'])

# 股票代码范围
stock_codes = ["000001.SZ", "000002.SZ", ..., "301603.SZ"]  # 替换为你的股票代码范围

for code in stock_codes:
    # 查找输入框并输入股票代码
    input_element = driver.find_element(By.CSS_SELECTOR, '.ant-input.ant-input-borderless')
    input_element.clear()  # 清除输入框
    input_element.send_keys(code)  # 输入股票代码
    input_element.send_keys(Keys.RETURN)  # 按Enter键提交查询
    
    # 等待页面加载(需要根据实际情况调整等待时间)
    time.sleep(3)
    
    # 解析页面获取ESG评级信息
    try:
        rating_element = driver.find_element(By.CSS_SELECTOR, '.style-module__resultConRight2-16WxH')
        rating = rating_element.text.strip()
        ws.append([code, rating])
    except Exception as e:
        print(f"Error retrieving data for {code}: {str(e)}")
        continue

# 保存Excel文件
wb.save("ESG_Ratings.xlsx")
driver.quit()

(三)第三个prompt——指定网页的交互动作:

嗯,现在这个代码是可以成功打开网页并且输入信息了。不过又有新的问题出现了。程序中是输入股票代码后按“enter”键执行搜索操作,但这个网站却不是这样。它需要输入后,点击选择输入结果对应的公司,再执行搜索。并且每次搜索后,需要点击右方那个“x”符号来清除输入的信息:

prompt:

我发现该网站查询后按“enter”键不会转到结果。我在搜索框输入股票代码“000001.SZ”后,下面会显示结果<div class="style-module__inputList-3kgSx"><div class="style-module__inputListItem-2k4TW"><p title="平安银行股份有限公司----000001.SZ">平安银行股份有限公司----000001.SZ</p></div></div>
我需要点击这一结果(在网页界面上文字显示为"平安银行股份有限公司----000001.SZ"),才会跳转到查询的结果

gpt回复:

了解了,既然需要点击搜索结果来完成查询,我们可以更新Selenium脚本来定位并点击这个搜索结果。根据你提供的元素信息,我们可以使用类名 style-module__inputListItem-2k4TW 来选择结果列表中的项目。

prompt:

我发现查询一个信息后,需要点击一个叉号图标以清楚查询的内容再重新输入,这个元素复制来的信息是<span class="style-module__inputClose-B3kTl"></span>

gpt回复:

好的,如果需要在每次查询之后点击一个叉号图标来清除已有查询内容,我们可以在脚本中加入这一步骤。这将确保在进行下一次查询前,搜索框是空的。

下面是添加了点击叉号图标清除内容的Selenium脚本:

from selenium import webdriver
from selenium.webdrivermon.keys import Keys
from selenium.webdrivermon.by import By
from selenium.webdriver.edge.service import Service
from openpyxl import Workbook
import time

# 初始化Edge webdriver
s = Service('[你的MicrosoftWebDriver.exe路径]')  # 替换为你的Edge WebDriver路径
driver = webdriver.Edge(service=s)
driver.get('https://esgratingsxgf/#/home')

# 创建Excel文件用于保存数据
wb = Workbook()
ws = wb.active
ws.append(['股票代码', 'ESG评级'])

# 股票代码范围
stock_codes = ["000001.SZ", "000002.SZ", ..., "301603.SZ"]  # 替换为你的股票代码范围

for code in stock_codes:
    # 查找输入框并输入股票代码
    input_element = driver.find_element(By.CSS_SELECTOR, '.ant-input.ant-input-borderless')
    input_element.clear()  # 清除输入框
    input_element.send_keys(code)  # 输入股票代码
    
    # 等待下拉列表出现
    time.sleep(1)  # 根据实际情况可能需要调整时间
    
    # 选择搜索结果中的第一个项并点击
    result_element = driver.find_element(By.CSS_SELECTOR, '.style-module__inputListItem-2k4TW')
    result_element.click()  # 点击跳转到查询结果
    
    # 等待页面加载(需要根据实际情况调整等待时间)
    time.sleep(3)
    
    # 解析页面获取ESG评级信息
    try:
        rating_element = driver.find_element(By.CSS_SELECTOR, '.style-module__resultConRight2-16WxH')
        rating = rating_element.text.strip()
        ws.append([code, rating])
    except Exception as e:
        print(f"Error retrieving data for {code}: {str(e)}")
    
    # 点击叉号图标清除输入框内容
    close_icon = driver.find_element(By.CSS_SELECTOR, '.style-module__inputClose-B3kTl')
    close_icon.click()
    time.sleep(1)  # 等待清除动作完成

# 保存Excel文件
wb.save("ESG_Ratings.xlsx")
driver.quit()

 (四)第四个prompt——显式等待:

好了,现在程序已经可以乖乖自动输入股票代码并查询了!但是由于等待时间是给定的,查询的速度有些慢,并且会报错:

{"name": "NoSuchElementException",
"message": "Message: no such element: Unable to locate element: {"method":"css selector","selector":".style-module__inputListItem-2k4TW"}

于是向gpt复制错误信息,并询问。gpt回复:

看来Selenium脚本中尝试定位元素 .style-module__inputListItem-2k4TW 时发生了 NoSuchElementException,这通常意味着在页面上没有找到指定的CSS选择器。可能的原因包括:

  1. 元素未加载完成:页面可能还没有完全加载完成就尝试查找元素。可以增加等待时间,或使用显式等待(Explicit Wait)确保元素可见后再进行操作。
  2. CSS选择器已更改:网页的结构可能已经变化,导致原有的CSS选择器不再适用。需要重新检查元素的CSS选择器。
  3. 条件不满足:输入的股票代码没有返回任何结果,因此相关的元素没有出现。

为了解决这个问题,你可以:

  • 使用显式等待:确保元素在操作前是可见的。下面是如何实现显式等待的示例代码:
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    # 等待元素变为可点击状态
    wait = WebDriverWait(driver, 10)  # 等待最长10秒
    result_element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.style-module__inputListItem-2k4TW')))
    result_element.click()
    

 (五)第五个prompt——检查报错并中止保存: 

已经可以舒适的运行了!但是由于数据量巨大,有时候一报错,之前查询到的就都白查了。为了让程序在报错后中止并保存已查询到的数据,进行进一步的询问:

我希望如果程序发生错误,则在excel中保存目前已经查询到的结果

gpt回复:

为了确保即使程序在查询过程中发生错误,已查询到的数据也能保存到Excel中,你可以在你的循环中添加一个更全面的错误处理机制。这样做可以捕获任何异常,并在异常发生时保存当前的数据并优雅地关闭浏览器和Excel文件。以下是你的代码的修改版本,加入了一个更全面的异常处理:

from selenium import webdriver
from selenium.webdrivermon.by import By
from selenium.webdriver.support.ui import WebDriverWait
from seleniummon.exceptions import WebDriverException
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.edge.service import Service
from openpyxl import Workbook, load_workbook
import time

# 初始化Edge webdriver
s = Service(r"C:\Program Files\Python312\edgedriver_win64\msedgedriver.exe")
driver = webdriver.Edge(service=s)
driver.get('https://esgratingsxgf/#/home')

# 尝试加载或创建工作簿
file_path = "ESG_Ratings.xlsx"
try:
    wb = load_workbook(file_path)
    ws = wb.active
except FileNotFoundError:
    wb = Workbook()
    ws = wb.active
    ws.append(['股票代码', 'ESG评级'])  # 添加标题行

# 股票代码范围
stock_codes = [
    "000528.SZ", "000529.SZ", "000530.SZ", "000531.SZ", "000532.SZ", 
    "000533.SZ", "000534.SZ", "000536.SZ", "000537.SZ", "000538.SZ", 
    "000539.SZ", "000541.SZ", "000543.SZ", "000544.SZ", "000545.SZ", 
    "000546.SZ", "000547.SZ", "000548.SZ", "000550.SZ", "000551.SZ", 
    "000552.SZ", "000553.SZ", "000554.SZ", "000555.SZ", "000557.SZ", 
    "000558.SZ", "000559.SZ", "000560.SZ"
]

try:
    for code in stock_codes:
        try:
            # 查找输入框并输入股票代码
            input_element = driver.find_element(By.CSS_SELECTOR, '.ant-input.ant-input-borderless')
            input_element.clear()
            input_element.send_keys(code)
            
            # 显式等待下拉列表可点击
            wait = WebDriverWait(driver, 10)
            try:
                result_element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.style-module__inputListItem-2k4TW')))
                result_element.click()
            except WebDriverException as inner_e:
                # 如果发生了任何WebDriver异常,重新查找并点击元素
                print(f"Encountered an error: {str(inner_e)}, retrying...")
                result_element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.style-module__inputListItem-2k4TW')))
                result_element.click()
            
            # 显式等待页面加载完毕
            wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.style-module__resultConRight2-16WxH')))
            
            # 获取并解析ESG评级信息
            rating_element = driver.find_element(By.CSS_SELECTOR, '.style-module__resultConRight2-16WxH')
            rating = rating_element.text.strip()
            ws.append([code, rating])
            
            # 清除输入框内容
            close_icon = driver.find_element(By.CSS_SELECTOR, '.style-module__inputClose-B3kTl')
            close_icon.click()
            time.sleep(1)  # 等待清除动作完成
        except Exception as e:
            print(f"An error occurred while processing stock code {code}: {str(e)}")

except Exception as e:
    print(f"An error occurred outside the stock code loop: {str(e)}")
finally:
    # 无论是否出现异常,都保存Excel文件并退出浏览器
    wb.save("ESG_Ratings.xlsx")
    driver.quit()

ok了,愉快输出数据。今天先整到这,目前够用了。

后续准备完成:直接读取excel中数据输入,并且直接输入到目标excel中。查询不到的数据用“-”表示

本文标签: 爬虫网页Pythongptselenium