👇 连享会 · 推文导航 | www.lianxh.cn
连享会课程 · 基于机器学习的因果推断方法
作者 :范思妤 (南京大学)邮箱 :fansiyu@smail.nju.edu.cn
温馨提示: 文中链接在微信中无法生效。请点击底部「阅读原文」 。或直接长按/扫描如下二维码,直达原文:
目录
1. 科创板审核问询披露
2. 爬虫实战
2.1 安装 selenium 及浏览器驱动
2.2 浏览器驱动配置使用
2.3 分析网页结构
2.4 获取 url 列表
2.5 遍历 url 列表爬取审核问询披露
3. 相关推文
1. 科创板审核问询披露 科创板试点的注册制改革,强调“以信息披露为核心”。为在发行上市审核坚持以信息披露为核心,把好上市企业入口质量关,上交所主要采用公开化问询式审核方式,即交易所提出问询的问题,发行人对这些问题进行回复和说明,中介机构对问询事项的核查过程和结论,以“一问一答”的方式及时向市场公开。
本文重点关注如何通过 Python 的 selenium
库爬取上述审核问询流程披露的原始文件,并在发行公司层面对问询与回复情况进行汇总统计。
2. 爬虫实战 2.1 安装 selenium 及浏览器驱动 在本文中,我们使用 Python 中的 selenium
库对网页进行爬取。selenium
通过创建模拟浏览器的方式进行爬取,可以完全模拟真实用户的动态操作。在配置好 Python 环境后,打开命令提示符,并键入如下命令安装 selenium
库:
pip install selenium
或者使用国内镜像源安装 selenium
库:
pip install selenium -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
接下来,我们需要安装浏览器驱动。此处我们主要讲解 Windows 系统安装 chrome 浏览器驱动的步骤和方法。其他系统及其他浏览器驱动的安装,请自行网络搜索相关教程。
首先,我们需要确定 chrome 浏览器版本。打开 chrome 浏览器,在新标签页输入 chrome://settings/help
进入设置界面,查看目前的版本信息。
在获取浏览器版本信息后,需下载对应版本的浏览器驱动。打开 chrome 浏览器 驱动下载地址 ,找到和目前版本最接近的驱动,Windows 系统用户需下载 win32 版本。
解压驱动文件包得到 chromedriver.exe
,保存到指定路径,并务必将当前路径添加到环境变量中(我的电脑 右键属性 高级系统设置
高级 环境变量 系统变量 Path)。
2.2 浏览器驱动配置使用 我们使用如下代码创建浏览器驱动对象。此外,我们可以根据爬虫目标网页调整浏览器选项,提供稳定运行环境。
from selenium import webdriverfrom selenium.webdriver import ChromeOptions CHROME_OPTIONS = webdriver.ChromeOptions() prefs = {"profile.managed_default_content_settings.images" :2 } # 1代表显示图片,2代表不显示图片 CHROME_OPTIONS.add_experimental_option("prefs" , prefs) CHROME_OPTIONS.add_experimental_option("excludeSwitches" ,["enable-automation" ]) CHROME_OPTIONS.add_experimental_option("useAutomationExtension" , False ) CHROME_OPTIONS.add_argument('--disable-blink-features=AutomationControlled' ) CHROME_DRIVER = r'D:/chromedriver/chromedriver.exe' # 此处为chromedriver.exe所在路径 # 声明浏览器 driver = webdriver.Chrome(executable_path=CHROME_DRIVER, options=CHROME_OPTIONS)
2.3 分析网页结构 首先,我们需要浏览待爬取的页面结构,并检查网页确定网页类型。
上交所科创板股票审核页面如下。最上方一行分类列示已递交申请的发行人的状态,我们的样本仅爬取已经有注册结果的发行人(即已经走完整个科创板审核问询流程。
所有发行人按照时间由近及远的顺序列示在页面表格中。每行发行人全称对应一个超链接,点击即进入发行人审核问询的详情页面。因此,我们整体的爬虫思路如下:
遍历目标链接列表爬取某一页面的特定信息,并储存到本地。 2.4 获取 url 列表 如上所述,我们仅爬取已经有注册结果的发行人。因此,首先需要用 selenium
自动化模拟鼠标点击操作,以点击页面上方的“注册结果”,获取跳转后的页面上的信息。
# 导入所需要的包 from selenium.webdriver.common.by import Byimport time# 请求页面 url = "http://kcb.sse.com.cn/renewal/" driver.get(url) # 通过Xpath定位到“注册结果”,并点击,等待页面加载 driver.find_element(By.XPATH,'//*[@id="select5"]/a/span[2]' ).click() time.sleep(3 )
通过加载后的检查页面,我们发现 url 就包含在发行人全称的 href 属性中。我们进行如下步骤的操作以获取完整的发行人 url 列表:
selenium
提供了多种元素定位方式,如 xpath,id,name 等。在本文中,我们用 Xpath 定位元素。具体步骤如下图,得到对应元素的 Xpath 后,通过语法 @href
选取元素属性。
代码如下:
# Xpath定位元素 all_url_list = [] url_xpath = '//*[@id="dataList1_container"]/tbody/tr/td[2]/a/@href' next_page = '//*[@id="dataList1_container_next"]/span' # 获取发行人url列表 for i in range(1 ,28 ): # 最大页数是28 print("正在抓取第%s页的内容" %i) html = driver.page_source tree = etree.HTML(html) url_list = tree.xpath(url_xpath) all_url_list.extend(url_list) time.sleep(1 ) if i<=26 : # 点击下一页 driver.find_element(By.XPATH,next_page).click() time.sleep(2 ) # 等待页面加载 else : pass # 最后一页没有“下一页” driver.quit()# 打印最后10个url,检查是否所有url爬取成功 for url in all_url_list[-10 :]: print(url)
2.5 遍历 url 列表爬取审核问询披露 在获取了全部发行人 url 列表之后,我们需要遍历 url 列表,获取特定发行人审核问询的详情页面。在这一页面,我们需要爬取的关键内容如下:
发行人基本信息:
审核问询披露文件:
代码如下:
#————爬取每个url对应的科创板发行上市公司页面————# # 导入所需的包 import timefrom
lxml import etreeimport pandas as pdfrom selenium import webdriverfrom selenium.webdriver.common.by import Byimport requestsimport osfrom urllib.request import urlretrieve# 在路径下创建文件夹 os.mkdir(r'./companies' )# 浏览器驱动配置及使用 CHROME_OPTIONS = webdriver.ChromeOptions() prefs = {"profile.managed_default_content_settings.images" :2 } # 1代表显示图片,2代表不显示图片 CHROME_OPTIONS.add_experimental_option("prefs" , prefs) CHROME_DRIVER = r'D:/chromedriver/chromedriver.exe' driver = webdriver.Chrome(executable_path=CHROME_DRIVER, options=CHROME_OPTIONS)# 发行人基本信息的Xpath定位 fullname_xpath = '//*[@id="issuer_full"]' shortname_xpath = '//*[@id="issuer_sec"]' broker_xpath = '//*[@id="sponsor_org"]/a' auditor_xpath = '//*[@id="accounts_org"]/a' lawyer_xpath = '//*[@id="law_firm"]/a' acceptdate_xpath = '//*[@id="step1F"]/div' inquirydate_xpath = '//*[@id="step2F"]/div' passdate_xpath = '//*[@id="step3F"]/div' # 注册制审核问询披露文件的Xpath定位 SECLetter_xpath = '//*[@id="yjhf"]/tbody/tr/td[2]/a' # 创建空列表以盛放后续爬虫信息 all_fullname = [] all_shortname = [] all_broker = [] all_auditor = [] all_lawyer = [] all_acceptdate = [] all_inquirydate = [] all_passdate = [] all_num_letter1 = [] all_num_letter2 = [] all_num_letter3 = []for url_item in all_url_list: url = 'http://kcb.sse.com.cn' + url_item driver.get(url) time.sleep(2 ) html = driver.page_source tree = etree.HTML(html) # 获取发行人基本信息的文本节点 fullname_list = tree.xpath(fullname_xpath + '/text()' ) all_fullname.append(fullname_list[0 ]) shortname_list = tree.xpath(shortname_xpath+ '/text()' ) all_shortname.append(shortname_list[0 ]) broker_list = tree.xpath(broker_xpath+ '/text()' ) content = ';' .join(broker_list) # 可能会有多个保荐机构,用分号链接,下同 all_broker.append(content) auditor_list = tree.xpath(auditor_xpath+ '/text()' ) content = ';' .join(auditor_list) all_auditor.append(content) lawyer_list = tree.xpath(lawyer_xpath+ '/text()' ) content = ';' .join(lawyer_list) all_lawyer.append(content) acceptdate_list = tree.xpath(acceptdate_xpath+ '/text()' ) all_acceptdate.append(acceptdate_list[0 ]) inquirydate_list = tree.xpath(inquirydate_xpath+ '/text()' ) all_inquirydate.append(inquirydate_list[0 ]) passdate_list = tree.xpath(passdate_xpath+ '/text()' ) all_passdate.append(passdate_list[0 ]) # 获取问询与回复信息的文本节点 SECLetter_list = tree.xpath(SECLetter_xpath + '/text()' ) # 获取问询与回复的href属性,为后续下载对应文件pdf做准备 SECLetter_url = tree.xpath(SECLetter_xpath + '/@href' ) # 为每一公司创建子文件夹,用以盛放分类后的文件pdf os.mkdir('./companies/' +fullname_list[0 ]) os.mkdir('./companies/' +fullname_list[0 ] + '/问询函和回函/' ) os.mkdir('./companies/' +fullname_list[0 ] + '/审计意见/' ) os.mkdir('./companies/' +fullname_list[0 ] + '/法律意见/' ) os.mkdir('./companies/' +fullname_list[0 ] + '/其他/' ) # 注册制审核问询披露文件的计数算子 count_letter1 = 0 count_letter2 = 0 count_letter3 = 0 #获取pdf文件方法1,用requests.get: for i in range(len(SECLetter_list)): url = SECLetter_url[i] r = requests.get('http:' + url) # 通过文件名称对文件进行分类,并计数 if ('发行人' in SECLetter_list[i]) or ('落实函' in SECLetter_list[i]) \ and ('会计' not in SECLetter_list[i]) and ('律师' not in SECLetter_list[i]) \ and ('法律' not in SECLetter_list[i]): with open('./companies/' +fullname_list[0 ] + '/问询函和回函/' +SECLetter_list[i]+'.pdf' , 'wb+' ) as f:
f.write(r.content) count_letter1 += 1 elif '会计' in SECLetter_list[i]: with open('./companies/' +fullname_list[0 ] + '/审计意见/' +SECLetter_list[i]+'.pdf' , 'wb+' ) as f: f.write(r.content) count_letter2 += 1 elif ('律师' in SECLetter_list[i]) or ('法律' in SECLetter_list[i]): with open('./companies/' +fullname_list[0 ] + '/法律意见/' +SECLetter_list[i]+'.pdf' , 'wb+' ) as f: f.write(r.content) count_letter3 += 1 else : with open('./companies/' +fullname_list[0 ] + '/其他/' +SECLetter_list[i]+'.pdf' , 'wb+' ) as f: f.write(r.content) all_num_letter1.append(count_letter1) all_num_letter2.append(count_letter2) all_num_letter3.append(count_letter3) ''' # 获取pdf文件方法2,用urlretrieve: # 以下代码仅做方法思路展示,未对pdf进行进一步分类 for i in range(len(SECLetter_list)): url = 'http:' + SECLetter_url[i] urlretrieve(url,filename = './科创板/companies/'+fullname_list[0]+'/'+SECLetter_list[i]+'.pdf') ''' driver.quit()# 将爬虫信息储存到本地excel文件 file = r".\科创板注册制信息披露.xlsx" final_data = [all_fullname,all_shortname,all_broker,all_auditor,all_lawyer,all_acceptdate, \ all_inquirydate,all_passdate,all_num_letter1,all_num_letter2,all_num_letter3] df = pd.DataFrame(final_data).T df.columns = ["公司全称" , "公司简称" , "保荐机构" , "会计师事务所" , "律师事务所" ,"受理日期" , \ "开始问询日期" ,"上市委通过日期" ,"问询与回函数量" ,"审计意见数量" ,"律师意见数量" ] df.to_excel(file, index = None )
最终,我们可以得到如下审核问询情况汇总及审核问询披露文件的原始 pdf:
注意 :以上代码在计算“问询与回函数量”、“审计意见数量”、“律师意见数量”时仅简单地计数页面上所列示的对应文件的数量,但并不代表发行人实际被问询次数。在现实中,若公司在季度末或者年末更新财务报表,则需根据更新后的财务报表向交易所重新提交以上文件。举个例子:《发行人及保荐机构回复意见》和《发行人及保荐机构回复意见(2022年半年报财务数据更新版)》本质上属于同一份回函的两个版本,计算一次问询次数,而不是两次。此处请读者仔细甄别。
3. 相关推文 Note:产生如下推文列表的 Stata 命令为: lianxh 爬虫, m
安装最新版 lianxh
命令: ssc install lianxh, replace
⏩ 专题课:文本分析-爬虫-机器学习-2022年4月 Python爬虫: 《经济研究》研究热点和主题分析 Python爬虫1:小白系列之requests和json Python爬虫2:小白系列之requests和lxml Python爬虫:爬取华尔街日报的全部历史文章并翻译 Python爬虫:从SEC-EDGAR爬取股东治理数据-Shareholder-Activism
课程推荐:因果推断实用计量方法 主讲老师:邱嘉平教授 🍓 课程主页 :https://gitee.com/lianxh/YGqjp
New! Stata 搜索神器:lianxh
和 songbl
GIF 动图介绍 搜: 推文、数据分享、期刊论文、重现代码 …… 👉 安装: . ssc install lianxh
. ssc install songbl
👉 使用: . lianxh DID 倍分法
. songbl all
🍏 关于我们 直通车: 👉【百度一下: 连享会 】即可直达连享会主页。亦可进一步添加 「知乎」,「b 站」,「面板数据」,「公开课」 等关键词细化搜索。