利用selenium、requests库爬取新浪财经股票信息和相应公司年度报告

一、明确爬取任务目标

由于我只知道新浪财经这一家财经类网站,所以决定爬取新浪财经网。爬取大概分为两层。第一层爬取各个股票的简略财经信息,并顺便获取相应公司的链接;第二层就利用上一层爬到的公司链接,爬取各个公司的年度报告。
我在第一层爬取到的信息类似于下面这样:

['600696', 'ST岩石', '2019-07-10', '0.02', '7435.61', '12.14', '738.57', '-46.04', '0.00', '2.46', '0.00', '26.87', '不分配', '明细', '--']

根据爬取到的股票id,可以生成第二层爬取的url。不过这个url并不是最终年度报告pdf资源的url,要获取这个链接还需要进一步的爬取。

二、selenium、requests优劣分析

seleniumrequests
爬取速度较慢较快
实现登录操作容易需要考虑一系列问题,很麻烦
页面中含有js代码生成元素可以直接获取元素很麻烦
如果网站有反爬虫机制较容易避开很麻烦

需要说明一下,有很多网站都会对用户的访问进行限速,当然也就限制了爬虫的速度,所以在实际爬取的时候selenium并不比requests慢很多。

三、“踩点”

财报查询
到新浪官网首页,选择“财报查询”,可以看到想要的股票列表。【相关链接】分析html文本,可以发现tbody中的每个tr标签,都对应一行股票信息
分析股票列表html
点击股票名称,可以进入相应公司的页面。然后,点击“公司咨询”>“年度报告”就可以看到公司的年度报告啦。
获取年度报告的页面

同样,可以知道年度报告的链接都在class=datelist的div标签下。
分析年度报告html
大概知道了这些信息后,就可以开始编写代码爬取信息啦。

四、代码实现

1、解析股票列表
parse_page实现了对股票列表html的解析。tbody > tr对应列表中的一行,而tr > td 则对应了每一行的各个信息。items是一个生成器,从中可以获取所有行。contents也是一个生成器,可以获取每一列。按照这样的方法解析股票简略信息。

    def parse_page(self):
        self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "#box > table > tbody")))
        html = self.browser.page_source
        doc = pq(html)
        items = doc("#box > table > tbody > tr").items()
        for item in items:
            # 从上到下爬取,最后一个item为页面链接
            if item('td').attr('id') != 'pages':
                info_list = []
                # href为详细信息链接
                href = item('td > a').attr('href')
                # contents为简略信息迭代器
                contents = item('td').items()
                for content in contents:
                    info_list.append(content.text())
                info_list.append(href)
                self.database.save(info_list)

说明:一、在解析html页面的时候,用了pyquery库。二、我自己做了一个存储网上爬取信息的Database类,最后一行的database.save方法就能够实现对信息的存储。三、代码中的href就是指向相应公司页面的url。
2、生成指向公司网页的url
因为网站的url大多数是具有一定规律的。简单分析一下就知道需要拼接什么样的url了。

base_url = 'http://vip.stock.finance.sina.com.cn/corp/go.php/vCB_Bulletin/stockid/{}/page_type/ndbg.phtml'
        stock_ids = self.read_database()
        for stock_id in stock_ids:
            report_url = base_url.format(stock_id)
            self.browser.get(report_url)
            self.find_report()

3.在公司网页中找到年度报告的页面
find_report函数能够自动找到年度报告所在页面,如果这个公司有年度报告,就调用下载年度报告的方法。

    def find_report(self):
        try:
            self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'datelist')))
            html = self.browser.page_source
            doc = pq(html)
            a_tags = doc('.datelist > ul > a').items()
            for a_tag in a_tags:
                report_name = a_tag.text()
                report_link = 'http://vip.stock.finance.sina.com.cn' + a_tag.attr('href')
                # 下载相应的财务报告,三种方式均可
                self.download_pdf_by_requests(report_name, report_link)
                # self.download_pdf_by_win32(report_name, report_link)
                # self.download_html(report_name, report_link)
        except TimeoutException:
            print("该股票无年度报告信息\n")

说明:一、该方法通过从a标签中获取链接来找到年度报告。二、上面代码提到的三种方法是我自己编写的,下面会有介绍。
4.下载年度报告
方法一,直接通过解析html获取年度报告,这样省去了下载的过程,速度比较快。缺点是有表格的地方会出现一些格式上的问题。

    def download_html(self, name, link):
        self.browser.get(link)
        # 去除文件名中的非法字符
        file_name = self.get_qualified_file_name(name, '.txt')
        file = open(file_name, 'w')
        try:
            content_html = self.browser.find_element_by_id('content').get_attribute('innerHTML')
            content = BeautifulSoup(content_html, 'html.parser').text
            file.writelines(content)
        except NoSuchElementException:
            print("下载出现了一些问题")
        file.close()

方法二,通过程序控制电脑的鼠标、键盘,实现对网站pdf资源的“另存为”操作,这样可以获取原滋原味的年度报告,可读性比较强。缺点是速度太慢了,而且由于程序会控制鼠标和键盘,为了保证程序正常运行,就没有办法自己操作鼠标、键盘去干别的事情了。

    def download_pdf_by_win32(self, name, link):
        file_name = self.get_qualified_file_name(name, '')
        self.browser.get(link)
        href = self.browser.find_element_by_link_text('下载公告').get_attribute('href')
        print(href)
        self.browser.get(href)
        time.sleep(5)
        try:
            # 左击链接框
            windll.user32.SetCursorPos(700, 50)
            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
            win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
            # 利用PyWin32操作鼠标键盘,实现pdf“另存为”
            # 设置文件保存的绝对路径
            file_path = os.path.dirname(os.path.realpath(__file__)) + '\\' + file_name
            # 将路径复制到剪切板
            win32clipboard.OpenClipboard()
            win32clipboard.EmptyClipboard()
            win32clipboard.SetClipboardText(file_path)
            win32clipboard.CloseClipboard()
            # 按下ctrl+s保存
            win32api.keybd_event(0x11, 0, 0, 0)
            win32api.keybd_event(0x53, 0, 0, 0)
            win32api.keybd_event(0x11, 0, win32con.KEYEVENTF_KEYUP, 0)
            win32api.keybd_event(0x53, 0, win32con.KEYEVENTF_KEYUP, 0)
            time.sleep(1)
            # ctrl+v粘贴保存路径
            win32api.keybd_event(0x11, 0, 0, 0)
            win32api.keybd_event(0x56, 0, 0, 0)
            win32api.keybd_event(0x11, 0, win32con.KEYEVENTF_KEYUP, 0)
            win32api.keybd_event(0x56, 0, win32con.KEYEVENTF_KEYUP, 0)
            time.sleep(1)
            # 按下回车保存
            win32api.keybd_event(0x0d, 0, 0, 0)
            win32api.keybd_event(0x0d, 0, win32con.KEYEVENTF_KEYUP, 0)
            time.sleep(5)
        except:
            print("下载出现了一些问题")

方法三,利用requests库直接向网站请求pdf资源。个人感觉这个方法最好,既能获得易读性较高的pdf报告,又不耽误我们操作电脑干别的事情,而且爬取速度介于方法一和方法三直接,也不是太慢。不过这个方法也有缺点,可能是新浪财经对爬虫的限制较少,所以采用requests请求才这么方便,如果到别的网站,可能会出现一些问题,还需要把下面这个代码完善一下。

 def download_pdf_by_requests(self, name, link):
        try:
            self.browser.get(link)
            href = self.browser.find_element_by_link_text('下载公告').get_attribute('href')
            file_name = self.get_qualified_file_name(name, '.pdf')
            response = requests.get(url=href, stream=True)
            response.raise_for_status()
            print("开始保存")
            with open(file_name, 'wb') as file:
                for content in response.iter_content():
                    file.write(content)
            print("结束保存")
        except:
            print("下载出现了问题")

五、程序源码
程序工程文件:report.zip
内含Database、Spider类及部分爬取下来的信息。

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

萌哒哒虎

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值