Python爬虫:从SEC-EDGAR爬取股东治理数据-Shareholder-Activism

文摘   教育   2024-11-24 22:01   中国  

👇 连享会 · 推文导航 | www.lianxh.cn

🍓 课程推荐:连享会:2025 寒假班
嘉宾:连玉君(初级|高级);杨海生(前沿)
时间:2025 年 1 月 13-24 日
咨询:王老师 18903405450(微信)

作者: 许梦洁 (Frankfurt School of Finance and Management)
邮箱: m.xu@fs.de


目录

  • 1. 获取 Cookies

    • 代码

  • 2. 获取 Json

  • 3. 分析 Json

  • 4. 爬取文件列表代码 - Python

  • 5. 列表爬取结果

  • 6. 分析 EDGAR 文件地址

  • 7. 爬取对应 EDGAR 文件代码 - Python

  • 7. 参考文献

  • 8. 相关推文



温馨提示: 文中链接在微信中无法生效。请点击底部「阅读原文」。或直接长按/扫描如下二维码,直达原文:

写论文的时候需要搞一个 shareholder activism 变量,但是学校没买。看了下 Brav et al. (2018, JFE, -PDF-),发现这个数据是直接从 SEC EDGAR 的 13D 文件整理的,等图书馆订要好几天,索性自己爬了。

1. 获取 Cookies

我一般用 Selenium 获取 cookies,这种方法自动化,而且几乎对任何网站都适用。对于 EDGAR,由于默认只显示文件名称,文件日期和涉及实体的名称。打开网页后,需要下拉页面勾选 CIK,FIle number 等其他你需要的选项。其中最关键的是 CIK ,这是链接 SEC File 和其他财务数据库 (Compustat,CRSP 等) 的关键识别变量。

打开 源网址  后呈现的页面如下

下拉默认只有三列数据:

勾选了其他数据栏后会呈现多列数据,相应的 Cookies 也会发现变化

代码

from selenium import webdriver
import time
import json

option = webdriver.FirefoxOptions()
option.add_argument('-headless')
driver = webdriver.Firefox(executable_path='/Users/mengjiexu/Dropbox/Pythoncodes/geckodriver')

driver.get("https://www.sec.gov/edgar/search/#/dateRange=custom&category=custom&startdt=2001-01-01&enddt=2021-05-27&forms=SC%252013D")
# 打开源网页

time.sleep(3)
driver.execute_script('window.scrollTo(0,500)')
# 向下拉到勾选位置
time.sleep(2)
driver.find_element_by_xpath("//input[@value='cik']").click() 
# 点选 CIK
driver.find_element_by_xpath("//input[@value='file-num']").click() 
# 点选 File number
time.sleep(2)

# 记录 cookies 并写入 txt 文件中
orcookies = driver.get_cookies()
print(orcookies)
cookies = {}
for item in orcookies:
    cookies[item['name']] = item['value']
with open("edgarcookies.txt""w"as f:
    f.write(json.dumps(cookies))

driver.close()

2. 获取 Json

从 search-index 中可以找到返回的 Json 源

翻到第二页,Fetch 得到 post 的参数信息,这里关键是是 headers 和 body

await fetch("https://efts.sec.gov/LATEST/search-index", {
    "credentials""omit",
    "headers": {
        "User-Agent""Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:89.0) Gecko/20100101 Firefox/89.0",
        "Accept""application/json, text/javascript, */*; q=0.01",
        "Accept-Language""en-US,en;q=0.5",
        "Content-Type""application/x-www-form-urlencoded; charset=UTF-8"
    },
    "referrer""https://www.sec.gov/",
    "body""{\"dateRange\":\"custom\",\"category\":\"custom\",\"startdt\":\"2001-01-01\",\"enddt\":\"2021-05-27\",\"forms\":[\"SC 13D\"],\"page\":\"2\",\"from\":100}",
    "method""POST",
    "mode""cors"
});

body 里包含了向服务器 post 的查询参数,包括

  • 查询起始日期 startdt / enddt
  • 文件类型 forms = SC 13D
  • 当前页数 page
  • 前续页数 from = 前一页码 $\times$ 100

3. 分析 Json

双击截图中的  search-index ,可以看到格式化的 Json,命名为 info。将每条结果命名为 case。这里主要提取的变量及对应的 Json 路径为:

  • 查询结果总数 info['hits']['total']['value']
  • 对于每条结果:
    • Shareholder Letter 接受实体  case['_source']['display_names'][0]
    • Shareholder Letter 发出实体  case['_source']['display_names'][1]
    • Shareholder Letter 接受实体  case['_source']['ciks'][0]
    • Shareholder Letter 发出实体  case['_source']['ciks'][1]
    • 文件 id  case['_id']
    • CIK
    • 文件序号  case['_source']['file_num']
    • 实体名称
    • 文件日期  case['_source']['file_date']
    • Adsh  case['_source']['adsh']

4. 爬取文件列表代码 - Python

import time
import json
import csv
import math
import requests
from tqdm import tqdm

headers = {
        "User-Agent""Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:88.0) Gecko/20100101 Firefox/88.0",
        "Accept""application/json, text/javascript, */*; q=0.01",
        "Accept-Language""en-US,en;q=0.5",
        "Content-Type""application/x-www-form-urlencoded; charset=UTF-8"
           }

def postpage(year, page):
    come = (page-1)*100
    post = "{\"dateRange\":\"custom\",\"category\":\"custom\",\"startdt\":\"%s-01-01\",\"enddt\":\"%s-12-31\",\"forms\":[\"SC 13D\"],\"page\":\"%s\",\"from\":%s}"%(year,year,page,come)
    return(post)

def getinfo(year, page):    
    with open("edgarcookies.txt""r")as f:
        cookies = f.read()
        cookies = json.loads(cookies)
        session = requests.session()

        url = "https://efts.sec.gov/LATEST/search-index"
        data = session.post(url,  headers=headers, cookies=cookies, data=postpage(year, page))
        time.sleep(1)

        info = json.loads(data.text)

        totalnum = info['hits']['total']['value']

        for case in info['hits']['hits']:
            with open('edgar13D_check.csv','a'as g:
                h = csv.writer(g)

                id = case['_id']
                try:
                    cik0 = case['_source']['ciks'][0]
                    cik1 = case['_source']['ciks'][1]
                except:
                    cik0 = ""
                    cik1 = ""
                root_form = case['_source']['root_form']
                file_num = case['_source']['file_num']
                try:
                    display_names_0 = case['_source']['display_names'][0]
                    display_names_1 = case['_source']['display_names'][1]
                except:
                    display_names_0 = ""
                    display_names_1 = ""
                file_date = case['_source']['file_date']
                adsh = case['_source']['adsh']

                out = [id,cik0,cik1,root_form, file_num, display_names_0, display_names_1,file_date,adsh]
                h.writerow(out)

        return(totalnum)

for year in range(20012022):
    totalnum = getinfo(year,1)
    print(totalnum)
    pagenum = math.ceil(totalnum/100)+1
    print("%s %s"%(year,pagenum))
    for page in tqdm(range(2,pagenum)):
        getinfo(year,page)

5. 列表爬取结果

6. 分析 EDGAR 文件地址

先来分析 EDGAR 文件地址的结构,一个典型的 EDGAR 文件地址

https://www.sec.gov/Archives/edgar/data/0001762728/000092189521001513/sc13da412475002_05272021.htm

主要包含三个部分

  • https://www.sec.gov/Archives/edgar/data/

  • 接受实体 CIK [上表列2]

  • id (e.g., 0001214659-21-005763:p519211sc13da7.htm) [上表列1] 中的 ":" 换成  "/", "-" 换成  ""

7. 爬取对应 EDGAR 文件代码 - Python

import os
import pandas as pd
import json
import csv
from tqdm import tqdm
import requests

df = pd.read_csv("edgar13d09-16.csv",header=0)

headers = {
        "User-Agent""Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:88.0) Gecko/20100101 Firefox/88.0",
        "Accept""application/json, text/javascript, */*; q=0.01",
        "Accept-Language""en-US,en;q=0.5",
        "Content-Type""application/x-www-form-urlencoded; charset=UTF-8"
           }

with open("edgarcookies.txt""r")as f:
 cookies = f.read()
 cookies = json.loads(cookies)
 session = requests.session()


for row in tqdm(df.iterrows()):
 url = row[1][0].replace(":","/").replace("-","")
 cik = row[1][1]
 filedate = row[1][7].replace('/','-')
 filename = "%s_%s"%(filedate,row[1][0])
 href=  "https://www.sec.gov/Archives/edgar/data/%s/%s"%(cik,url)
 data = session.get(href,  headers=headers, cookies=cookies)
 with open("/Users/mengjiexu/Dropbox/edgar13d/%s"%filename,'wb'as g:
  g.write(data.content)

7. 参考文献

  • Brav, Alon, Wei Jiang, Song Ma, and Xuan Tian. 2018. “How Does Hedge Fund Activism Reshape Corporate Innovation?” Journal of Financial Economics 130 (2): 237–64. https://doi.org/10.1016/j.jfineco.2018.06.012.

8. 相关推文

Note:产生如下推文列表的 Stata 命令为:
lianxh 爬虫 爬取
安装最新版 lianxh 命令:
ssc install lianxh, replace

  • 专题:文本分析-爬虫
    • Stata爬虫:爬取地区宏观数据
    • Stata爬虫:爬取A股公司基本信息
    • Python:爬取东方财富股吧评论进行情感分析
    • Stata爬虫-正则表达式:爬取必胜客
    • Python爬虫: 《经济研究》研究热点和主题分析
  • 专题:Python-R-Matlab
    • Python:爬取巨潮网公告
    • Python:爬取上市公司公告-Wind-CSMAR
    • Python 调用 API 爬取百度 POI 数据小贴士——坐标转换、数据清洗与 ArcGIS 可视化
    • Python 调用 API 爬取百度 POI 数据
    • Python: 批量爬取下载中国知网(CNKI) PDF论文



尊敬的老师 / 亲爱的同学们:

连享会致力于不断优化和丰富课程内容,以确保每位学员都能获得最有价值的学习体验。为了更精准地满足您的学习需求,我们诚挚地邀请您参与到我们的课程规划中来。 请您在下面的问卷中,分享您 感兴趣的学习主题或您希望深入了解的知识领域 。您的每一条建议都是我们宝贵的资源,将直接影响到我们课程的改进和创新。 我们期待您的反馈,因为您的参与和支持是我们不断前进的动力。感谢您抽出宝贵时间,与我们共同塑造更加精彩的学习旅程!https://www.wjx.cn/vm/YgPfdsJ.aspx# 再次感谢大家宝贵的意见!




New! Stata 搜索神器:lianxh 和 songbl  GIF 动图介绍
搜: 推文、数据分享、期刊论文、重现代码 ……
👉 安装:
  . ssc install lianxh
  . ssc install songbl
👉  使用:
  . lianxh DID 倍分法
  . songbl all



🍏 关于我们

  • 连享会 ( www.lianxh.cn,推文列表) 由中山大学连玉君老师团队创办,定期分享实证分析经验。
  • 直通车: 👉【百度一下: 连享会】即可直达连享会主页。亦可进一步添加 「知乎」,「b 站」,「面板数据」,「公开课」 等关键词细化搜索。


连享会
连玉君老师团队分享,主页:lianxh.cn。白话计量,代码实操;学术路上,与君同行。
 最新文章