一、开始前的探索
背景是这样:本人没有学过爬虫,目前需要做一项数据录入的任务。基本内容就是,在网站上输入股票代码,点击提示框内出现的公司名称,再根据查询到的结果录入对应的数据。由于这个工作操作具有重复性,并且查询量巨大,于是考虑采用爬虫录入试试。
首先,我什么都不知道的情况下向gpt询问:
我想要写一个程序,帮助我从这个网站:https://esgratings.ccxgf.com/#/home
提取股票代码为000001.SZ到301603.SZ的每年的ESG评级信息,并录入到excel表格的相关位置中,请帮助我实现
这是gpt给出的代码:
import requests
from bs4 import BeautifulSoup
from openpyxl import Workbook
# 设置网站URL和股票代码
url = "https://esgratings.ccxgf.com/#/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.com')
# 输出响应的文本
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.com')
# 打印网页标题
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动态加载的内容。在这种情况下,仅使用
requests
和BeautifulSoup
可能不足以获取信息,因为它们无法执行JavaScript。我们可以考虑使用Selenium
这个工具,它能够模拟浏览器行为,包括输入股票代码、提交查询以及等待页面加载完毕。步骤1: 安装Edge WebDriver
- 确保你的Edge浏览器是最新版本。
- 下载与你的Edge版本对应的Edge WebDriver。你可以在这里下载:Edge WebDriver。
- 将下载的WebDriver放在一个方便的位置,例如你的项目目录或者任何一个系统的环境变量
PATH
包含的目录。步骤2: 安装Selenium
如果你还没有安装Selenium,可以通过运行以下命令来安装:
pip install selenium
步骤3: 修改脚本以使用Edge
下面是使用Edge WebDriver的修改后的脚本。你需要替换webdriver路径和对应的CSS选择器,以适应你的具体需求:
from selenium import webdriver
from selenium.webdriver.common.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://esgratings.ccxgf.com/#/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.webdriver.common.keys import Keys
from selenium.webdriver.common.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://esgratings.ccxgf.com/#/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.webdriver.common.keys import Keys from selenium.webdriver.common.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://esgratings.ccxgf.com/#/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选择器。可能的原因包括:
- 元素未加载完成:页面可能还没有完全加载完成就尝试查找元素。可以增加等待时间,或使用显式等待(Explicit Wait)确保元素可见后再进行操作。
- CSS选择器已更改:网页的结构可能已经变化,导致原有的CSS选择器不再适用。需要重新检查元素的CSS选择器。
- 条件不满足:输入的股票代码没有返回任何结果,因此相关的元素没有出现。
为了解决这个问题,你可以:
- 使用显式等待:确保元素在操作前是可见的。下面是如何实现显式等待的示例代码:
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.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.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://esgratings.ccxgf.com/#/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中。查询不到的数据用“-”表示