专栏名称: Python开发者
人生苦短,我用 Python。伯乐在线旗下账号「Python开发者」分享 Python 相关的技术文章、工具资源、精选课程、热点资讯等。
目录
相关文章推荐
Python爱好者社区  ·  同事年底绩效是C,提离职领导死活不让走,后来 ... ·  昨天  
Python爱好者社区  ·  刚刚,奥特曼晒出早产娃引爆全网!两个爸爸孕育 ... ·  2 天前  
Python爱好者社区  ·  640页的python教程 ·  昨天  
小小的python学习社  ·  Python100道真题题库 ·  昨天  
Python爱好者社区  ·  DeepSeek 被放弃了,阿里牛逼! ·  3 天前  
51好读  ›  专栏  ›  Python开发者

从零开始的 Python 爬虫速成指南

Python开发者  · 公众号  · Python  · 2017-01-25 21:42

正文

(点击 上方蓝字 ,快速关注我们)


来源:舞鹤

segmentfault.com/a/1190000008135000

如有好文章投稿,请点击 → 这里了解详情



本文主要内容:以最短的时间写一个最简单的爬虫,可以抓取论坛的帖子标题和帖子内容。


本文受众:没写过爬虫的萌新。


入门


0.准备工作


需要准备的东西: Python、scrapy、一个IDE或者随便什么文本编辑工具。


1.技术部已经研究决定了,你来写爬虫。


随便建一个工作目录,然后用命令行建立一个工程,工程名为miao,可以替换为你喜欢的名字。


scrapy startproject miao


随后你会得到如下的一个由scrapy创建的目录结构



在spiders文件夹中创建一个python文件,比如miao.py,来作为爬虫的脚本。

内容如下:


import scrapy

class NgaSpider ( scrapy . Spider ) :

name = "NgaSpider"

host = "http://bbs.ngacn.cc/"

# start_urls是我们准备爬的初始页

start_urls = [

"http://bbs.ngacn.cc/thread.php?fid=406" ,

]

# 这个是解析函数,如果不特别指明的话,scrapy抓回来的页面会由这个函数进行解析。

# 对页面的处理和分析工作都在此进行,这个示例里我们只是简单地把页面内容打印出来。

def parse ( self , response ) :

print response . body


2.跑一个试试?


如果用命令行的话就这样:


cd miao

scrapy crawl NgaSpider


你可以看到爬虫君已经把你坛星际区第一页打印出来了,当然由于没有任何处理,所以混杂着html标签和js脚本都一并打印出来了。


解析


接下来我们要把刚刚抓下来的页面进行分析,从这坨html和js堆里把这一页的帖子标题提炼出来。

其实解析页面是个体力活,方法多的是,这里只介绍xpath。


0.为什么不试试神奇的xpath呢


看一下刚才抓下来的那坨东西,或者用chrome浏览器手动打开那个页面然后按F12可以看到页面结构。

每个标题其实都是由这么一个html标签包裹着的。举个例子:


[合作模式] 合作模式修改设想


可以看到href就是这个帖子的地址(当然前面要拼上论坛地址),而这个标签包裹的内容就是帖子的标题了。

于是我们用xpath的绝对定位方法,把class='topic'的部分摘出来。


1.看看xpath的效果


在最上面加上引用:


from scrapy import Selector


把parse函数改成:


def parse ( self , response ) :

selector = Selector ( response )

# 在此,xpath会将所有class=topic的标签提取出来,当然这是个list

# 这个list里的每一个元素都是我们要找的html标签

content_list = selector . xpath ( "//*[@class='topic']" )

# 遍历这个list,处理每一个标签

for content in content_list :

# 此处解析标签,提取出我们需要的帖子标题。

topic = content . xpath ( 'string(.)' ). extract_first ()

print topic

# 此处提取出帖子的url地址。

url = self . host + content . xpath ( '@href' ). extract_first ()

print url


再次运行就可以看到输出你坛星际区第一页所有帖子的标题和url了。


递归


接下来我们要抓取每一个帖子的内容。


这里需要用到python的yield。


yield Request(url=url, callback=self.parse_topic)


此处会告诉scrapy去抓取这个url,然后把抓回来的页面用指定的parse_topic函数进行解析。


至此我们需要定义一个新的函数来分析一个帖子里的内容。


完整的代码如下:


import scrapy

from scrapy import Selector

from scrapy import Request

class NgaSpider ( scrapy . Spider ) :

name = "NgaSpider"

host = "http://bbs.ngacn.cc/"

# 这个例子中只指定了一个页面作为爬取的起始url

# 当然从数据库或者文件或者什么其他地方读取起始url也是可以的

start_urls = [

"http://bbs.ngacn.cc/thread.php?fid=406" ,

]

# 爬虫的入口,可以在此进行一些初始化工作,比如从某个文件或者数据库读入起始url

def start_requests ( self ) :

for url in self . start_urls :

# 此处将起始url加入scrapy的待爬取队列,并指定解析函数

# scrapy会自行调度,并访问该url然后把内容拿回来

yield Request ( url = url , callback = self . parse_page )

# 版面解析函数,解析一个版面上的帖子的标题和地址

def parse_page ( self , response ) :

selector = Selector ( response )

content_list = selector . xpath ( "//*[@class='topic']" )

for content in content_list :

topic = content . xpath ( 'string(.)' ). extract_first ()

print topic

url = self . host + content . xpath ( '@href' ). extract_first ()

print url

# 此处,将解析出的帖子地址加入待爬取队列,并指定解析函数

yield Request ( url = url , callback = self . parse_topic )

# 可以在此处解析翻页信息,从而实现爬取版区的多个页面

# 帖子的解析函数,解析一个帖子的每一楼的内容

def parse_topic ( self , response ) :

selector = Selector ( response )

content_list = selector . xpath ( "//*[@class='postcontent ubbcode']" )

for content in content_list :

content = content . xpath ( 'string(.)' ). extract_first ()

print content

# 可以在此处解析翻页信息,从而实现爬取帖子的多个页面


到此为止,这个爬虫可以爬取你坛第一页所有的帖子的标题,并爬取每个帖子里第一页的每一层楼的内容。

爬取多个页面的原理相同,注意解析翻页的url地址、设定终止条件、指定好对应的页面解析函数即可。


Pipelines——管道


此处是对已抓取、解析后的内容的处理,可以通过管道写入本地文件、数据库。


0.定义一个Item


在miao文件夹中创建一个items.py文件。


from scrapy import Item , Field

class TopicItem ( Item ) :

url = Field ()

title = Field ()

author = Field ()

class ContentItem ( Item ) :

url = Field ()

content = Field ()

author = Field ()


此处我们定义了两个简单的class来描述我们爬取的结果。


1. 写一个处理方法


在miao文件夹下面找到那个pipelines.py文件,scrapy之前应该已经自动生成好了。


我们可以在此建一个处理方法。


class FilePipeline ( object ) :

## 爬虫的分析结果都会由scrapy交给此函数处理

def process_item ( self , item , spider ) :

if isinstance ( item , TopicItem ) :

## 在此可进行文件写入、数据库写入等操作

pass

if isinstance ( item , ContentItem ) :

## 在此可进行文件写入、数据库写入等操作

pass

## ...

return item


2.在爬虫中调用这个处理方法。


要调用这个方法我们只需在爬虫中调用即可,例如原先的内容处理函数可改为:


def parse_topic ( self , response ) :

selector = Selector ( response )

content_list = selector . xpath ( "//*[@class='postcontent ubbcode']" )

for content in content_list :

content = content . xpath ( 'string(.)' ). extract_first ()

## 以上是原内容

## 创建个ContentItem对象把我们爬取的东西放进去

item = ContentItem ()

item [ "url" ] = response . url

item [ "content" ] = content

item [ "author" ] = "" ## 略

## 这样调用就可以了

## scrapy会把这个item交给我们刚刚写的FilePipeline来处理

yield item


3.在配置文件里指定这个pipeline


找到settings.py文件,在里面加入


ITEM_PIPELINES = {

'miao.pipelines.FilePipeline' : 400 ,

}


这样在爬虫里调用


yield item


的时候都会由经这个FilePipeline来处理。后面的数字400表示的是优先级。

可以在此配置多个Pipeline,scrapy会根据优先级,把item依次交给各个item来处理,每个处理完的结果会传递给下一个pipeline来处理。


可以这样配置多个pipeline:


ITEM_PIPELINES = {

'miao.pipelines.Pipeline00' : 400 ,

'miao.pipelines.Pipeline01' : 401 ,

'miao.pipelines.Pipeline02' : 402 ,

'miao.pipelines.Pipeline03' : 403 ,

## ...

}


Middleware——中间件







请到「今天看啥」查看全文