如果想抓数据,就需要有爬虫程序,业内叫crawler或者spider。
有各种语言版本的开源爬虫,c++, Java, php,在github上搜一下,以"spider c++"为关键字,有245个开源爬虫,以"spider java"为关键字,有48个。那python呢?156个。
爬虫技术在业界已经很成熟了,有很多开源框架,在它们的帮助下写爬虫可以很快,几个小时就能写一个不错的东东用。爬虫技术也会很复杂,如果要做分布式抓取和全文检索,一般使用Nutch。
最有名的Python爬虫框架是Scrapy,这个名字也蛮有意思的,估计是Spider,Crawler,python各取部分字符组合起来的,它的官方主页在http://scrapy.org/。
1. 安装Scrapy
安装Scrapy很简单,linux系统的话,一条语句就可以了,"sudo pip install Scrapy"。通常python在Linux各发行版上都是默认安装的。pip是python的包管理工具,执行install命令后,它会从网上下载最新版本的Scrapy安装。安装完毕,在命令行输入命令"scrapy version",会打印scrapy的版本,表明安装成功。
2. 生成项目目录
如果要抓取大众点评网,需要先创建项目。选择一个空目录,比如在我的电脑上是/tmp/scrapy-test,在命令行输入"scrapy startproject crawdp",startproject是scrapy的一个命令。执行后,在/tmp/scrapy-test目录会出现一个新目录crawdp,它包含scrawdp项目所需要的一切东东,如源代码和配置文件。运行"tree crawdp",可以看到整个目录结构。
那么,"startproject""创建项目"这个高大上字眼背后的真相是什么呢?其实不复杂,就是创建一个项目名的目录和它的几个子目录,然后复制几个指定的文件到这些目录,再把这些文件里的几个特定字符串替换成项目名。这块的代码在scrapy源代码的scrapy/command/commands目录下的startproject.py文件里,而在"tree crawdp"看到的文件,它们的原型在scrapy/templates/project/module目录下,如settings.py.tmpl文件,把它里面的字符串"$project_name"用"crawdp"替换,再把文件名改成settings.py,就是crawdp的settings.py文件。
像settings.py.tmpl这样的文件,又称为模板文件,把模板里的变量用字符串替换掉,叫渲染(render)。在web server的开发中也同样使用这种技术,前端工程师设计html文件,里面包含形如"$project_name"之类的变量,保存成模板文件,而服务器在运行的时候,用运行时产生的字符串替换掉模板里的变量,再把替换后的内容发给浏览器,就是我们看到的网页,所以叫动态页面。
3. 第一个spider
开始写第一个spider,这是一个非常简单的spider,只有13行代码。
在/tmp/scrapy-test/crawdp/crawdp/spiders目录下,创建文件cityid_spider.py,内容如下:
-----------------------------------------
from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
class CityidSpider(BaseSpider):
name = "cityid_spider"
start_urls = ["http://www.dianping.com/shanghai/food"]
def parse(self, response):
hxs = HtmlXPathSelector(response)
xs = hxs.select(‘//ul[@class=\"nc_list\"]/li/a/@href‘)
x = xs[0]
cityid = x.extract().split(‘/‘)[3]
print "\n\n\ncityid = %s\n\n\n" % cityid
-----------------------------------------
返回到/tmp/scrapy-test/crawdp/目录,在这个目录下执行"scrapy crawl cityid_spider",可以看到打印出来的结果是"cityid = 1",在默认配置下,顺带会打印很多log信息,所以我在这句加了几个换行符,让它显示得清楚一点。
注意,这里有几个关键点:
a. cityid_spider.py这个文件,必须放在/tmp/scrapy-test/crawdp/crawdp/spiders目录下,放在别的地方,scrapy找不到。
b. 源代码里,name = "cityid_spider"这句必须有,这里指定了spider的名字,scrapy靠名字识别不同的spider。
c. 必须在/tmp/scrapy-test/crawdp/下执行"scrapy crawl cityid_spider",在别的目录下不行。
其他的,可以把class CityidSpider类名换成别的,没关系,也可以cityid_spider.py文件名换成别的名字,也没关系,不影响效果。
这个spider是一切spider的基本型,更复杂的spider都是在它的基础上逐渐添加更多功能做出来的。
4. 这个spider是干什么的
在大众点评网,每个城市都有一个数字代号,比如上海是1,北京是2,深圳是7。它家的总部在上海,所以上海是1号。如果想抓更多城市的餐厅,就需要知道城市代号。上海的城市代号,可以从http://www.dianping.com/shanghai/food抓取。在浏览器打开http://www.dianping.com/shanghai/food,在左侧的“商区”下面,有“陆家嘴”,在它上面点击右键,选择“审查元素”,如果你用的是chrome,浏览器会开一个窗口,用高亮色定位到陆家嘴对应的html元素,这个元素包含一个超级链接,叫"/search/category/1/10/r801"
,那么上海的cityid就是超级链接里的category后面"1",而这个链接,是嵌套在一个固定的层次式的html元素里,也就是形如代码里形如"//ul[@class=\"nc_list\"]/li/a/@href"的结构,这种写法叫xpath。
执行"scrapy crawl cityid_spider"的时候,spider开始运行,它先检查spider源代码里的“start_urls = ["http://www.dianping.com/shanghai/food"]”,根据这个url,从大众点评网上抓取html文件内容,存在response里,然后调用parse函数,从response里用xpath解析出所有符合"//ul[@class=\"nc_list\"]/li/a/@href"的html元素,取第一个,得到一个类似“/search/category/1/10/r801”的字符串,然后将它以‘/‘为间隔做分割,取第3个,就是"1",就是cityid,这就是parse函数的前四条语句做的事情。
这块写的略有一点不人性化,术语比较多。那么,想做抓取的话,至少要懂一点html,css,web server,xpath,略微有点基础就行。这些东西在这里就不展开了,找本入门书看看就可以了。
一个网站的诞生02--用Scrapy抓取数据