PhantomJS+Selenium+Scrapy抓取巨潮资讯网企业信息
本文首发于我的博客:gongyanli.com
代码传送门:https://github.com/Gladysgong/cninfo
简书: https://www.jianshu.com/p/b5ef0e7e2b87
CSDN: https://mp.csdn.net/mdeditor/79759833
首先说说我的目标把,就是抓取巨潮资讯网上一些上市农业企业的基本信息,主要是对页面的公司概况、高管人员、十大股东这几个板块的信
息进行抓取,如图。要抓取的上市农业企业的名单已经准备好了,但是同时要拿到的这些农业企业的url地址。本来考虑的是做一个整站提取url,
但是再想一想,这个网站包含了太多上市公司的信息,即使拿到了,也需要慢慢找。加上我们要抓取的农业企业不多,所以分析页面结果后,手动
整理他们的url,算是本爬虫的一个缺陷。
巨潮资讯地址:http://www.cninfo.com.cn/information/companyinfo_n.html?brief?szmb000998上面这个就是公司概况的url地址,而高管人员只需要把brief换成management,十大股东只需要把brief换成shareholders,而后面的后缀
szmb000998这个是手动整理的,这个szmb没看出什么意思,后面的数字是当前公司的股票代码。经过分析,发现网页是动态加载的,里面的内容都是通过js来控制iframe进行展现的,通过scrapy中response.body获取网页的返回结果中,
没有完美所需要的内容,所以我们需要用selenium。
一、PhantomJS–PhantomJS安装验证
PhantomJS是一个基于webkit内核的没有界面的浏览器,所以它和chrome、Firefox这些没有什么差别,只是没有界面而已啦,所以并无高深之处。
关于它的安装及验证非常简单,大家可以参考我的另一篇文章,标题处去点击链接把。
二、Selenium–Selenium的使用
Selinium是一个自动化的测试工具,用它可以驱动浏览器执行特定的操作,比如点击按钮,切换到ifame中等操作,同时能够获取到浏览器渲染后的
源码。所以它对于那些用JavaScript渲染的网页来讲,Selenium是再合适不过了。
崔庆才的博客中有一篇详细讲解了Selenium的用法,可以参考。
三、通过Scrapy来使用Selenium
1.中间件
首先看一下我的工作目录把,没有什么特点,scrapy典型的工作目录,唯一不一样的是middlewares文件夹,里面存放的是我自定义的中间件。通过
自定义的中间件去把scrapy原本的中间件覆盖,从而用我们自己实现的功能去替换scrapy原有的功能。
我的中间件代码如下:打开PhantomJS浏览器,请求url地址,睡眠,接着切换iframe,因为我要获取的公司概况信息就在id='i_nr'的这个ifame
中,再睡眠,等待浏览器渲染出这个ifame中的内容,然后再body中保存此网页的源码,最后利用HtmlResponse把body传送离开。
`from selenium import webdriver
from scrapy.http import HtmlResponse
import timeclass JavaScriptMiddleware(object):def process_request(self, request, spider):if spider.name == 'CninfoSpider':print('PhantomJS1 is starting...')driver = webdriver.PhantomJS(executable_path=r'E:\Program Files\phantomjs-2.1.1-windows\bin\phantomjs.exe')driver.get(request.url)time.sleep(1)driver.switch_to.frame('i_nr')time.sleep(2)body = driver.page_sourceprint("访问:", request.url)return HtmlResponse(driver.current_url, body=body, encoding='utf-8')elif spider.name == 'CninfoManaSpider':print('PhantomJS2 is starting...')driver = webdriver.PhantomJS(executable_path=r'E:\Program Files\phantomjs-2.1.1-windows\bin\phantomjs.exe')driver.get(request.url)time.sleep(1)driver.switch_to.frame('i_nr')time.sleep(2)body = driver.page_sourceprint("访问:", request.url)return HtmlResponse(driver.current_url, body=body, encoding='utf-8')else:return
`
2.数据解析–cninfo.py
之后,我们就可以回到cninfo.py文件中对内容进行解析了。重写__init__,使用webdriver打开PhantomJS浏览器。重写start_requests方法,
拼接url,同时可以自定义返回函数parse。
`# --*-- coding:utf-8 -*-
import scrapy
from scrapy import Request
from scrapy.spiders import Spider
from selenium import webdriver
from ..items import AgriBasicItem# 巨潮资讯网--上市农业企业基本信息
class CninfoSpider(Spider):name = 'CninfoSpider'def __init__(self):self.broswer = webdriver.PhantomJS(executable_path=r'E:\Program Files\phantomjs-2.1.1-windows\bin\phantomjs.exe')self.broswer.set_page_load_timeout(30)def closed(self, spider):print('spider closed!')self.broswer.close()def start_requests(self):myurls = ['szmb000998', 'szsme002041', 'szsme002772', 'szcn300087', 'szcn300189', 'szcn300511','shmb600108','shmb600313', 'shmb600354', 'shmb600359','shmb600371', 'shmb600506', 'shmb600598', 'shmb601118', 'szmb000592', 'szsme002200','szsme002679','shmb600265', 'szmb000735', 'szsme002234','szsme002299', 'szsme002321', 'szsme002458', 'szsme002477', 'szsme002505', 'szsme002714','szsme002746', 'szcn300106', 'szcn300313', 'szcn300498','shmb600965', 'shmb600975', 'szmb000798', 'szsme002086', 'szsme002696', 'szmb200992','szcn300094','shmb600097', 'shmb600257', 'shmb600467', 'szmb000711', 'szmb000713']start_urls = [('http://www.cninfo.com.cn/information/companyinfo_n.html?brief?' + each) for each in myurls]for url in start_urls:yield Request(url=url, callback=self.parse)def parse(self, response):item = AgriBasicItem()item['full_name'] = response.xpath('//div[@class="clear2"]/div[@class="zx_left"]/div[2]/table/tbody/tr[1]/td[2]/text()').extract()[0] # 公司名称item['en_name'] = response.xpath('//div[@class="clear2"]/div[@class="zx_left"]/div[2]/table/tbody/tr[2]/td[2]/text()').extract()[0] # 英文名称item['cn_name'] = item['full_name'] # 中文名称item['nation'] = 'china' # 国别item['address'] = response.xpath('//div[@class="clear2"]/div[@class="zx_left"]/div[2]/table/tbody/tr[3]/td[2]/text()').extract()[0] # 注册地址item['established_time'] = None # 成立时间item['stock_time'] = response.xpath('//div[@class="clear2"]/div[@class="zx_left"]/div[2]/table/tbody/tr[13]/td[2]/text()').extract()[0] # 上市时间# shareholders = scrapy.Field() # 主要股东item['industry'] = response.xpath('//div[@class="clear2"]/div[@class="zx_left"]/div[2]/table/tbody/tr[8]/td[2]/text()').extract()[0] # 行业(经营类别)# managers = scrapy.Field() # 主要管理人员item['parent_company'] = None # 母公司item['subsidiaries'] = None # 子公司item['offical_website'] = response.xpath('//div[@class="clear2"]/div[@class="zx_left"]/div[2]/table/tbody/tr[12]/td[2]/text()').extract()[0] # 官网item['phone'] = response.xpath('//div[@class="clear2"]/div[@class="zx_left"]/div[2]/table/tbody/tr[10]/td[2]/text()').extract()[0] # 公司电话item['fax'] = response.xpath('//div[@class="clear2"]/div[@class="zx_left"]/div[2]/table/tbody/tr[11]/td[2]/text()').extract()[0] # 公司传真item['Twitter'] = None # Twitteritem['stock_code'] = response.xpath('//div[@class="zx_info"]/form/table/tbody/tr/td[1]/text()').extract()[0] # 股票代码item['abbr'] = response.xpath('//div[@class="zx_info"]/form/table/tbody/tr/td[1]/text()').extract()[1] # 公司简称yield item`
3.数据持久化–pipelines.py
把抓取下来的数据存进mongo数据库,实现数据的持久化。setting中数据库配置如下:
MONGO_HOST = '127.0.0.1' # 主机ip
MONGO_PORT = 27017 # 端口号
MONGO_DB = 'agriEn' # 数据库名称
`import pymongo
from scrapy.conf import settings
from .items import AgriBasicItem
from .items import AgriManaItemclass CninfoPipeline(object):def __init__(self):self.client = pymongo.MongoClient(host=settings['MONGO_HOST'], port=settings['MONGO_PORT'])self.db = self.client[settings['MONGO_DB']]self.cninfo_base = self.db['cninfo_base']self.cninfo_mana = self.db['cninfo_mana']self.cninfo_share = self.db['cninfo_share']def process_item(self, item, spider):if isinstance(item, AgriBasicItem):try:if item['full_name']:item = dict(item)self.cninfo_base.insert(item)print("insert baseinfo success !")return itemexcept Exception as e:spider.logger.exception("insert failed")elif isinstance(item,AgriManaItem):if item['managers']:item = dict(item)self.cninfo_mana.insert(item)print("insert managers success !")return item`
4.配置文件–setting.py
ROBOTSTXT_OBEY = FalseDOWNLOADER_MIDDLEWARES = {
# 键是中间件类的路径,值是中间的顺序
'cninfo.middlewares.middleware.JavaScriptMiddleware': 543,
# 禁止内置的中间件
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None }# 记得开启pipelines的调用
ITEM_PIPELINES = {
'cninfo.pipelines.CninfoPipeline': 300,}
四、缺陷
在这个爬虫中,其实出现了蛮多问题的,有些解决了,有些没有,记录一下,加深印象,还有感觉代码好垃圾。
1.缺陷1
上市农业企业的名字,以及名字的url链接手动整理的,因为只有40来个企业,所以才会用这个方法。本来是想通过Scarpy的CrawlSpider抓取,
抓取时通过Rule来控制所需要的农业企业,但是发现实在没有什么规律,只会把巨潮资讯上所有上市企业的url都获取下来,所以最后手动整理的
这40多个农业企业,希望日后能找到更简便的办法。
2.缺陷2
对于网页中的高管人员信息抓取中,本来是想思考放在一个爬虫中获取到的,但是仔细分析后发现,公司概况和高管人员分别对应着不同的url,
然后不同的url下再对应中动态加载iframe。url对比如下:
http://www.cninfo.com.cn/information/companyinfo_n.html?brief?szmb000998
http://www.cninfo.com.cn/information/companyinfo_n.html?management?szmb000998
这样子的话,就涉及到我需要在Selenuim中点击按钮,然后再渲染id='i_nr'的iframe,而且不同页面中iframe名字都叫i_nr。我试过这个
办法,但是拿回的源码并不是高管人员页面的源码,依然是公司概况页面的源码,也许是我方法用的不对,有待仔细研究。
所以我又在cninfo_mana.py中又写了一个爬虫,从而单独来获取高管人员页面的信息。
3.缺陷3
对于十大股东页面,按理说我应该在写一个py文件来单独获取它的页面信息,这样子就ok了,实际上我也是这么做的。但是爬虫运行是,却发
现我拿不到股东的信息,因为我发现当请求http://www.cninfo.com.cn/information/companyinfo_n.html?shareholders?
szmb000998时,首先切换到id='i_nr'的iframe中,但是随后股东的详细信息又在一个id='i_nr'的ifrma中,相当于这里有两个iframe,
我在中间件试了试两个这样子切换iframe,但是很遗憾我没拿到我想要的东西,源代码还是停留在第一层iframe中,所以最后我放弃了,没有
拿十大股东的信息,这个问题智能留着我以后解决了。
4.缺陷4
self.broswer = webdriver.PhantomJS(executable_path=r'E:\Program Files\phantomjs-2.1.1-windows\bin\phantomjs.exe')
这个代码在中间件和爬虫代码中都有,说明两次打开了浏览器,致使性能降低。
五、其他项目
其实我之前还用Selenium写过一个项目,用过抓取FAO的国家分类信息,以前习惯不好,做事不记录,导致做完就忘,只有个模糊的印象。
今天把之前那个项目找到了,重新运行了一下,但是抓不到东西了,我看看了网站的结构没变,应该是在动态加载方面变化了,等有时间的时候
看看究竟哪里变了,再把代码优化一下,附上github地址,有兴趣可以参考一下。如果有帮助,给个star把,好不要脸,第一次求star。
https://github.com/Gladysgong/fao
六、后续
后来我又写了一篇文章——用Python下载巨潮资讯农业上市企业的年报PDF文件(二),有兴趣的可以看看。
PhantomJS+Selenium+Scrapy抓取巨潮资讯网企业信息相关推荐
- 批量爬取巨潮资讯网中“贵州茅台”相关公告的PDF文件。
1 需求 批量爬取巨潮资讯网中"贵州茅台"相关公告的PDF文件. 2 代码实现 import reimport requests from selenium import webd ...
- python3爬取巨潮资讯网的年报数据
python3爬取巨潮资讯网的年报数据 前期准备: 需要用到的库: 完整代码: 前期准备: 巨潮资讯网有反爬虫机制,所以先打开巨潮资讯网的年报板块,看看有什么解决办法. 巨潮咨询年报板块 可以通过这样 ...
- 基于python+selenium+Chrome自动化爬取巨潮资讯网A股财务报表
转自同学的博客 引言: 网页爬虫分为静态网页爬虫和动态网页爬虫,前者是指索要获取的网页内容不需要经过js运算或者人工交互, 后者是指获取的内容必须要经过js运算或者人工交互.这里的js运算可能是aja ...
- 巧用selenium爬取巨潮资讯公司数据
巧用selenium爬取巨潮资讯公司数据 立项背景:在做深度学习的过程中利用python进行建模,需要数据来训练模型. 项目目标:通过运用python的selenium模块,爬取巨潮资讯网站关于公司的 ...
- selenium爬取巨潮资讯指定领域下所有上市公司的数据并存储到csv文件
selenium爬取巨潮资讯指定领域下所有上市公司的数据并存储到csv文件 from selenium.webdriver import Chrome #引入selenium中的Chrome from ...
- python3爬取巨潮资讯网站年报数据
python3爬取巨潮资讯网站年报数据 2018年年底巨潮资讯http://www.cninfo.com.cn改版了,之前实习生从网上找的脚本不能用了,因此重新修改了下爬取脚本.最初脚本的原链接忘了, ...
- 爬虫|巨潮资讯网上市公司年报爬取
爬虫|巨潮资讯网上市公司年报爬取 import pandas as pd from selenium import webdriver from selenium.webdriver.common.k ...
- python3爬取数据_python3爬取巨潮资讯网站年报数据
python3爬取巨潮资讯网站年报数据 2018年年底巨潮资讯http://www.cninfo.com.cn改版了,之前实习生从网上找的脚本不能用了,因此重新修改了下爬取脚本.最初脚本的原链接忘了, ...
- python 爬虫 requests+BeautifulSoup 爬取巨潮资讯公司概况代码实例
第一次写一个算是比较完整的爬虫,自我感觉极差啊,代码low,效率差,也没有保存到本地文件或者数据库,强行使用了一波多线程导致数据顺序发生了变化... 贴在这里,引以为戒吧. # -*- coding: ...
- 请用Python语言写一个巨潮资讯网批量下载PDF的程序
下面是一个使用 Python 的简单程序,可以批量下载巨潮资讯网上的 PDF 文件: import requests import os# 巨潮资讯网 PDF 文件的 URL 前缀 url_prefi ...
最新文章
- Android内存泄漏简介
- pandas的to_csv()使用细节和一些参数
- MyEclipse for Mac快捷键
- 数据结构练习 00-自测3. 数组元素循环右移问题 (20)
- 这一团糟的代码,真的是我写的?!
- C++重载下标运算符
- javascript设计模式-学习笔记
- [转载收藏]三层式开发中的层次划分
- Java annotation 自定义注释@interface的用法 转载记录
- 音视频即时通讯解决方案
- ajax 更新局部视图,使用Ajax局部更新Razor页面的实例代码
- 订单超时、定时任务解决方案和思路
- 【计算机视觉】不来试试图片轮廓提取?
- ASP.NET Core中如何显示[PII is hidden]的隐藏信息
- word表格无法跨页断开,内容被隐藏到了页面下方,如何解决?
- win系统一键安装redmine+配置+插件安装配置教程【原创-亲测安装成功-一枚测试喵】
- sfc /scannow是什么意思,有什么作用?(转载)
- 判断一个整数是否为回文数
- 微信自动发朋友圈源码
- 中华人民共和国刑事诉讼法