Chinaunix首页 | 论坛 | 博客
  • 博客访问: 966997
  • 博文数量: 403
  • 博客积分: 27
  • 博客等级: 民兵
  • 技术积分: 165
  • 用 户 组: 普通用户
  • 注册时间: 2011-12-25 22:20
文章分类

全部博文(403)

文章存档

2016年(3)

2015年(16)

2014年(163)

2013年(222)

分类: Python/Ruby

2014-05-27 17:58:29

文章来源:

CUHK 上学期有门课叫做 Semantic Web,课程 project 是要搜集整个系里面的教授信息,输入到一个系统里,能够完成诸如“如果选了A教授的课,因时间冲突,B教授的哪些课不能选”、“和A教授实验室相邻的实验室都是哪些教授的”这一类的查询。这就是所谓的“语义网”了啊。。。然而最坑爹的是,所有这些信息,老师并没有给一个文档或者数据库,全要靠自己去系主页上搜集。唯一的想法是写个爬虫,令人悲哀的是,所有做这个 project 的同学,都是纯人肉手工完成,看得我只想扶墙。。。

从网页中抓取特定信息,我觉得这是一个普遍性的问题,以后经常会遇到。幸亏那个 project 只是需要我们系的所有教授的信息,大家人工也就算了。如果需要抓取的信息是海量的,举个栗子,把淘宝上所有的商品目录抓下来,那岂不是要吐血而亡?我决定好好把爬虫研究一下。


之前波波写过一个 java 程序,利用  去解析团购网站 meituan.com 然后把每天的团购信息存到数据库里。稍微改改再爬爬拉手糯米,做个前端,一个团购导航站就问世了。我把程序跑了一下,全自动搜集,不算太复杂。

但是,我觉得 java 太啰嗦,不够简洁。Python 这个脚本语言开发起来速度很快,一个活生生的例子是因有关政策 verycd 开始自我阉割,有网友为了抢救资源,把整个 verycd 站爬了下来,镜像为。看了一下爬虫 ,其实挺简单。使用方法:

python sitecopy.py com

看看效果:

1. 获取html页面

其实,最基本的抓站,两句话就可以了

import urllib2 content = urllib2.urlopen('').read()

这样可以得到整个 html 文档,关键的问题是我们可能需要从这个文档中获取我们需要的有用信息,而不是整个文档。这就需要解析充满了各种标签的 html。

2. 解析 html

SGMLParser

Python 默认自带 HTMLParser 以及 SGMLParser 等等解析器,前者实在是太难用了,我就用 SGMLParser 写了一个示例程序:

import urllib2
from sgmllib import SGMLParser  
class ListName(SGMLParser):
 def __init__(self):
        SGMLParser.__init__(self)
 self.is_h4 = ""
 self.name = []
 def start_h4(self, attrs):
 self.is_h4 = 1
 def end_h4(self):
 self.is_h4 = ""
 def handle_data(self, text):
 if self.is_h4 == 1:
 self.name.append(text)  
content = urllib2.urlopen('').read()
listname = ListName()
listname.feed(content)
for item in listname.name:
 print item.decode('gbk').encode('utf8')

很简单,这里定义了一个叫做 ListName 的类,继承 SGMLParser 里面的方法。使用一个变量 is_h4 做标记判定 html 文件中的 h4 标签,如果遇到 h4 标签,则将标签内的内容加入到 List 变量 name 中。解释一下 start_h4() 和 end_h4() 函数,他们原型是 SGMLParser 中的

start_tagname(self, attrs)
end_tagname(self)

tagname 就是标签名称,比如当遇到 

,就会调用 start_pre,遇到 
,就会调用end_pre。attrs 为标签的参数,以 [(attribute, value), (attribute, value), ...] 的形式传回。

输出:

虚拟票务
数码市场
家电市场
女装市场
男装市场
童装童鞋
女鞋市场
男鞋市场
内衣市场
箱包市场
服饰配件
珠宝饰品
美容市场
母婴市场
家居市场
日用市场
食品/保健
运动鞋服
运动户外
汽车用品
玩具市场
文化用品市场
爱好市场
生活服务

如果有乱码,可能是与网页编码不一致,需要替换最后一句 deconde() 的参数,我在香港淘宝默认用的是繁体编码。各位可以 copy 上面的代码自己试试,把淘宝的商品目录抓下来,就是这么简单。稍微改改,就可以抽取二级分类等其他信息。

pyQuery

 是 jQuery 在 python 中的实现,能够以 jQuery 的语法来操作解析 HTML 文档,十分方便。使用前需要安装,easy_install pyquery 即可,或者 Ubuntu 下

sudo apt-get install python-pyquery

以下例子:

from pyquery import PyQuery as pyq
doc=pyq(url=r'')
cts=doc('.market-cat')
for i in cts:
 print '====',pyq(i).find('h4').text() ,'===='
 for j in pyq(i).find('.sub'):
 print pyq(j).text() , 
 print '\n'

BeautifulSoup

有个头痛的问题是,大部分的网页都没有完全遵照标准来写,各种莫名其妙的错误令人想要找出那个写网页的人痛打一顿。为了解决这个问题,我们可以选择著名的  来解析 html 文档,它具有很好的容错能力。

还是用例子来说明吧。我在工作时遇到一个需求,是要查询某一个 NS 服务器的所有域名,通过搜索我找到  这个网站可以提供域名服务器的信息。那么就要写个爬虫来抓查询结果了,看上去查询结果页面就是一个 ol 列表,并不复杂。

sitedossier-result

有点棘手的是如果结果太多,它会进行分页。爬虫需要能够(1)自动翻页(2)知道最后一页。最后一页有“End of list”字符串,所以可以通过正则表达式搞定。

代码开源在  上,几个函数都还算清晰可读,这里就不贴了。感觉这段脚本还是有点小用处的,比如你可以查到迄今为止有 304373 个域名在用 DNSPOD 解析,或者你想看看新浪 SAE 上到底有多少个网站,又或者了解下百度有些什么域名,观察域名规律抢注近似域名神马的……

用法:

$ python crawler_ns.py -ns dns.baidu.com
# 保存结果到文件:
$ python crawler_ns.py -ns dns.baidu.com >> result.txt

BeautifulSoup 功能强大,我还在研究学习。有进展会更新本文。

阅读(1652) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~