最近由于公司业务上的需求,要网络采集一些数据,并格式化以供应用的调取,前期想到用正则表达式来对网页格式串进行过滤和抓取,在进行了一系列尝试之后放弃,
原因是太繁琐了,而且对于每种网页都需要写特定的表达式,不可通用。
后面在查找相关资料时,发现python也提供一个类似jquery的包,叫做pyquery,可用以进行网络抓取,遂安装研究了一下,发现确实挺好用,不用写复杂的表达式即可
对数据进行抓取和过滤。
下面就以一个网页为例,来抓取指定格式的数据,并记录过程。
http://yunvs.com/list/mai_1.html
我要抓取这个网页上的数据,如下图:
我现在需要抓取股票与概念的关系,以便应用可以方便的通过股票查找其所属的概念,也可以通过热点概念定位相关股票。
那么,应用所需要的数据格式应该是这样的:
股票代码
股票名称
概念名称
002011 盾安环境 多晶硅
002011 盾安环境 分布式能源
002011 盾安环境 核电
002011 盾安环境 核电通风与空气处
002011 盾安环境 太阳能
002011 盾安环境 低碳经济
002011 盾安环境 珠港澳大桥概念
002011 盾安环境 地热
002011 盾安环境 地热能
002011 盾安环境 供热管网改造
002011 盾安环境 疫苗储存
002011 盾安环境 干热岩
但是从网页上我们可以看到,数据是以行的形式来展现的,单只股票后面跟了多个概念,且概念与概念之间以空格为分隔符,所以我们不仅仅要对数据进行抓取,同时还要对其格式进行处理。
下面,我们就通过python的第三方扩展包pyquery来对此网页进行抓取。
1.安装pyquery包
具体的安装过程就不在这里详述了,python的包安装可以通过一个工具叫做easy_install来进行安装和管理,大家百度一下即可得到相关资料。
pyquery包解析html以来lxml包,所以这里要安装pyquery和lxml两个包才可使用pyquery.
pyquery的官网地址:
ht
tp://pythonhosted.org//pyquery/api.htm
l ,上面有详细的每个api的使用方法
2.导入pyquery包
from pyquery import PyQuery as pq
from lxml import etree
3.加载需要解析的数据源
v_source=pq("hello") ---直接加载一个html串
v_source=pq(filename=path_to_html_file) ---加载位于指定路径下的html文件
v_source=pq(url='http://yunvs.com/list/mai_1.html') ---加载url地址直接进行解析
在这里我们就直接使用第三种方式,直接加载网页来进行数据抓取,这样显得更直观和实用。
4.分析要解析的html网页代码
以
http://yunvs.com/list/mai_1.html 为例,我们要抓取股票和概念的数据,那么查看其网页源码,将要解析的代码段摘出来,如下:
- <tr height=\"30\" > <td align=\"center\"><a href=\"http://yunvs.com/600401\" target=\"_blank\">600401</a></td>
- <td align=\"center\"><a href=\"http://yunvs.com/600401\" target=\"_blank\">海润光伏</a></td>
- <td align=\"center\">17876.8</td>
- <td align=\"center\">2005.74</td>
- <td align=\"center\"><font color=\"#C00\"><b>+791.28%</b></font></td>
- <td align=\"left\"><a href=\"http://yunvs.com/theme/t640.html\" target=\"_blank\">光伏</a> <a href=\"http://yunvs.com/theme/t323.html\" target=\"_blank\">太阳能</a> <a href=\"http://yunvs.com/theme/t225.html\" target=\"_blank\">阶梯电价受益</a> <a href=\"http://yunvs.com/theme/t105.html\" target=\"_blank\">多晶硅</a> <a href=\"http://yunvs.com/theme/t285.html\" target=\"_blank\">券商(龙头)</a> <a href=\"http://yunvs.com/theme/t230.html\" target=\"_blank\">金太阳工程</a> </td>
- </tr>
可以看到,单只股票的数据都是包含在一个大的 tr标签里面,那么我们第一步过滤就是将网页里面所有的tr段截取出来。
第一步过滤可以这样写:
v_source=pq(url='http://yunvs.com/list/mai_1.html')
v_source('tr') ----这里就是将所有以tr打头的html段过滤出来
想测试的话,可以用以下的语句来输出结果。
for data in v_source('tr'):
print pq(data).html() ---直接输出截取串的html对象,看着更加直观
输出如下:
PS:如果报错UnicodeEncodeError: 'gbk' codec can't encode character,则在程序头部加入字符集支持 #coding=utf-8
基本上我们需要的核心块都被抓取出来了
我们也可以以text文本的方式输出,这样就去掉了html标记
- #coding=utf-8
from pyquery import PyQuery as pq
from lxml import etree
from pyquery import PyQuery as pq
from lxml import etree
v_source=pq(url='http://yunvs.com/list/mai_1.html')
for data in v_source('tr'):
print pq(data).text() -----以text文本的方式进行输出
-
结果如下:
- 代码 股票 市场关注度↓ 平均MAI MAI相对变动 相关概念
- 600401 海润光伏 17417.6 2006.94 +767.87% 光伏 太阳能 阶梯电价受益 多晶硅 券商(龙头) 金太阳工程
- 002143 高金食品 10391.3 1339.54 +675.74% 肉制品 猪肉 成渝特区 猪肉加工 农地林地 传媒
- 002070 众和股份 6022.89 611.21 +885.4% 印染 锂精矿 海西 己内酰胺
- 300213 佳讯飞鸿 5896.39 374.88 +1472.87% 光通信 探月工程 三季报预增 铁路营改增 铁路营改增
- 600732 上海新梅 4529.39 894.01 +406.64% 迪士尼 创投
- 600303 曙光股份 4139.83 131.78 +3041.47% 客车 新能源客车 东北振兴 乙肝疫苗 校车 公路运输 公路运输 镍碳超级电容电池
- 002130 沃尔核材 3749.11 1875.24 +99.93% 核电 抗辐射 新型建材 新材料 珠三角区 电线电缆 铁基超导 合肥综合保税区 中英核电合作 超导材料 新合成三维材料
- 002113 天润控股 3741.65 569.31 +557.23% 足球
- 600315 上海家化 3638.3 1602.57 +127.03% 化妆品 消毒 抗病毒产品 丙烯腈 信托 纯碱 三季报预增 易信 民族品牌 草甘膦 苯胺 己内酰胺
- 002009 天奇股份 3566.27 412.28 +765.01% 风电叶片 低碳经济 江苏沿海地区 机器人 工业自动化 智能物流骨干网 供热管网改造 物流 报废车回收 万达文化旅游城 循环经济
- 000018 中冠A 3354.35 172.67 +1842.63% 印染 工业用地
- 000036 华联控股 3131.94 184.24 +1599.93% PTA(化工) 前海开发 珠三角区 深圳土地创新 家具建材 前海规划 工业用地 集体建设用地
- 002356 浩宁达 2798.2 257.86 +985.16% 智能电表 智能电网 电力改革
- 300249 依米康 2796.64 713.37 +292.03%
- 300282 汇冠股份 2721.66 488.97 +456.61% 教育装备 联想供应链 触摸屏 游戏机
- 300279 和晶科技 2669.16 586.76 +354.9% 手势控制 云计算 无锡物联网 智能家居 物联网
- 300010 立思辰 2452.26 636.86 +285.06% 软件外包 网络安全 饮料包装 网络教育 棱镜计划 在线教育 空中交通管理 电子政务 职业教育 去IOE 阿里巴巴上市 信息安全 高校 智慧医疗 WAPI WAPI 国家安全
- 300220 金运激光 2411.08 873.71 +175.96% 激光武器 激光 3D打印
- 600754 锦江股份 2360.15 387.22 +509.51% 迪士尼 迪士尼旅游消费 酒店餐饮 上海金融创新 镁矿 国企改革 旅游行业
- 600016 民生银行 2338.14 1424.41 +64.15% 股份制银行 海洋工程 二维码 海洋产品养殖 棚户改造 民生电商 奢侈品 人民币升值 农业合作社 电子商务 电商 支付宝 无人岛 互联网金融 三季报预增 聚宝盆 T+0 券商 券商 影子银行 金枪鱼 金枪鱼 泉州金改 余额宝 金改 博鳌 港股互通 微信理财通 儿童节 小额贷款
可以看到,我们需要的数据以行记录的形式已经抓取下来了。
如果我们想获取每一行的第一个记录应该如何得到呢?
这里就要分析一下代码了,还是以这段代码为例:
- <tr height=\"30\" > <td align=\"center\"><a href=\"http://yunvs.com/600401\" target=\"_blank\">600401</a></td>
- <td align=\"center\"><a href=\"http://yunvs.com/600401\" target=\"_blank\">海润光伏</a></td>
- <td align=\"center\">17876.8</td>
- <td align=\"center\">2005.74</td>
- <td align=\"center\"><font color=\"#C00\"><b>+791.28%</b></font></td>
- <td align=\"left\"><a href=\"http://yunvs.com/theme/t640.html\" target=\"_blank\">光伏</a> <a href=\"http://yunvs.com/theme/t323.html\" target=\"_blank\">太阳能</a> <a href=\"http://yunvs.com/theme/t225.html\" target=\"_blank\">阶梯电价受益</a> <a href=\"http://yunvs.com/theme/t105.html\" target=\"_blank\">多晶硅</a> <a href=\"http://yunvs.com/theme/t285.html\" target=\"_blank\">券商(龙头)</a> <a href=\"http://yunvs.com/theme/t230.html\" target=\"_blank\">金太阳工程</a> </td>
- </tr>
在最外面的tr段中,包含了6个小的td段,我们需要的数据都内嵌在这6个小的td段中,那么我们如果想调出单个td段的对象,可用如下代码测试:
- #coding=utf-8
from pyquery import PyQuery as pq
from lxml import etree
from pyquery import PyQuery as pq
from lxml import etree
v_source=pq(url='http://yunvs.com/list/mai_1.html')
for data in v_source('tr'):
print pq(data).text()
for i in range(len(data)):
print pq(data).find('td').eq(i).text()
-
截取一段输出如下:
600315 上海家化 3645.76 1602.69 +127.48% 化妆品 消毒 抗病毒产品 丙烯腈 信托 纯碱 三季报预增 易信 民族品牌 草甘膦 苯胺 己内酰胺
600315 ----eq(0) 组内第一个元素
上海家化 ---eq(1) 组内第二个元素
3645.76 ----eq(2) 组内第三个元素
1602.69 ----eq(3) 组内第四个元素
+127.48% ----eq(4) 组内第五个元素
化妆品 消毒 抗病毒产品 丙烯腈 信托 纯碱 三季报预增 易信 民族品牌 草甘膦 苯胺 己内酰胺 ---组内第六个元素
以上抓取代码解释如下:
pq(data).find('td') 意思是对第一次过滤的 v_source('tr')代码再次在内部进行二次查找,过滤'td'打头的段,可以看到一共有5个。
len(data) 输出代码里面的元素个数
pq(data).find('td').eq(i) 获取此段代码过滤后的第i个元素
从上面的输出可以看到,我们需要的数据就是第1,2,6 三个元素,那么我们的代码可以这样写:
- #coding=utf-8
from pyquery import PyQuery as pq
from lxml import etree
from pyquery import PyQuery as pq
from lxml import etree
v_source=pq(url='http://yunvs.com/list/mai_1.html')
for data in v_source('tr'):
print pq(data).find('td').eq(0).text()
print pq(data).find('td').eq(1).text()
print pq(data).find('td').eq(5).text()
-
输出结果如下(截取一段):
600401
海润光伏
光伏 太阳能 阶梯电价受益 多晶硅 券商(龙头) 金太阳工程
看到没有,我们需要的信息已经逐渐清晰了,目前股票代码和股票名称已经能解析出来后进行准确的定位,剩下的就是将以空格隔开的概念单个解析出来与股票进行匹配。
有了上面的经验,我们继续观察第一段代码,以便对概念进行第三次解析
- <tr height=\"30\" > <td align=\"center\"><a href=\"http://yunvs.com/600401\" target=\"_blank\">600401</a></td>
- <td align=\"center\"><a href=\"http://yunvs.com/600401\" target=\"_blank\">海润光伏</a></td>
- <td align=\"center\">17876.8</td>
- <td align=\"center\">2005.74</td>
- <td align=\"center\"><font color=\"#C00\"><b>+791.28%</b></font></td>
- <td align=\"left\"><a href=\"http://yunvs.com/theme/t640.html\" target=\"_blank\">光伏</a> <a href=\"http://yunvs.com/theme/t323.html\" target=\"_blank\">太阳能</a> <a href=\"http://yunvs.com/theme/t225.html\" target=\"_blank\">阶梯电价受益</a> <a href=\"http://yunvs.com/theme/t105.html\" target=\"_blank\">多晶硅</a> <a href=\"http://yunvs.com/theme/t285.html\" target=\"_blank\">券商(龙头)</a> <a href=\"http://yunvs.com/theme/t230.html\" target=\"_blank\">金太阳工程</a> </td>
- </tr>
可以看到,概念的信息在'td'代码段里面又分了几组,组与组之间以'a'标签进行分隔,那么需要对'td'组内的第6个元素再次进行过滤,可用如下代码进行测试:
- #coding=utf-8
from pyquery import PyQuery as pq
from lxml import etree
from pyquery import PyQuery as pq
from lxml import etree
v_source=pq(url='http://yunvs.com/list/mai_1.html')
for data in v_source('tr'):
print pq(data).find('td').eq(0).text()
print pq(data).find('td').eq(1).text()
print pq(data).find('td').eq(5).text()
v_ind = pq(data).find('td').eq(5)
for i in range(len(pq(v_ind).find('a'))): --输出概念元祖内以'a'打头标记的元素个数
print pq(v_ind).find('a').eq(i).text() --输出对应的元素
-
v_ind = pq(data).find('td').eq(5)
pq(v_ind).find('a')
以上两段代码是关键,第一行代码用于摘出概念模块的html代码,如下:
- <td align=\\\"left\\\"><a href=\\\"http://yunvs.com/theme/t640.html\\\" target=\\\"_blank\\\">光伏</a> <a href=\\\"http://yunvs.com/theme/t323.html\\\" target=\\\"_blank\\\">太阳能</a> <a href=\\\"http://yunvs.com/theme/t225.html\\\" target=\\\"_blank\\\">阶梯电价受益</a> <a href=\\\"http://yunvs.com/theme/t105.html\\\" target=\\\"_blank\\\">多晶硅</a> <a href=\\\"http://yunvs.com/theme/t285.html\\\" target=\\\"_blank\\\">券商(龙头)</a> <a href=\\\"http://yunvs.com/theme/t230.html\\\" target=\\\"_blank\\\">金太阳工程</a> </td>
第二行代码则用于在上面的代码里面继续过滤以'a'为标签的元素,这样就把之前以空格分隔的数据单个过滤出来了。
从上至下,我们依次得到了股票代码,股票名称以及单个的概念名称,那么我们将这三者组合在一起并输出,可以像这样写代码:
- #coding=utf-8
from pyquery import PyQuery as pq
from lxml import etree
from pyquery import PyQuery as pq
from lxml import etree
v_source=pq(url='http://yunvs.com/list/mai_1.html')
for data in v_source('tr'):
v_code = pq(data).find('td').eq(0).text()
v_name = pq(data).find('td').eq(1).text()
v_ind = pq(data).find('td').eq(5)
for i in range(len(pq(v_ind).find('a'))):
v_indname = pq(v_ind).find('a').eq(i).text()
print v_code
print v_name
print v_indname
-
这样,我们在最里面的循环里面即可将股票和概念单对单组合,最后可将结果写入数据库或文件系统中
输出结果如下:
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/22166274/viewspace-1183937/,如需转载,请注明出处,否则将追究法律责任。