上回,我装了环境
也就是一对乱七八糟的东西
装了pip,用pip装了virtualenv,建立了一个virtualenv,在这个virtualenv里面,装了Django,创建了一个Django项目,在这个Django项目里面创建了一个叫做web的阿皮皮。

接上回~

第二部分,编写爬虫。

工欲善其事,必先利其器。

bashapt-get install vim # 接上回,我们在screen里面是root身份哦~

当然了,现在我要想一个采集的目标,为了方便,我就选择segmentfault吧,这网站写博客不错,就是在海外上传图片有点慢。

这个爬虫,就像我访问一样,要分步骤来。 我先看到segmentfault首页,然后发现里面有很多tags,每个tags下面,才是一个一个的问题的内容。

所以,爬虫也要分为这几个步骤来写。 但是我要反着写,先写内容爬虫,再写分类爬虫, 因为我想。

2.1 编写内容爬虫

首先,给爬虫建立个目录,在项目里面和app同级,然后把这个目录变成一个python的package

bashmkdir ~/python_spider/sfspider
touch ~/python_spider/sfspider/__init__.py

以后,这个目录就叫爬虫包了

在爬虫包里面建立一个spider.py用来装我的爬虫们

bashvim ~/python_spider/sfspider/spider.py

一个基本的爬虫,只需要下面几行代码:

(代码下面会提供)
然后呢,就可以玩玩我们的“爬虫”了。
进入python shell

python>>> from sfspider import spider
>>> s = spider.SegmentfaultQuestionSpider('1010000002542775')
>>> s.url
>>> 'http://segmentfault.com/q/1010000002542775'
>>> print s.dom('h1#questionTitle').text()
>>> 微信JS—SDK嵌套选择图片和上传图片接口,实现一键上传图片,遇到问题

看吧,我现在已经可以通过爬虫获取segmentfault的提问标题了。下一步,为了简化代码,我把标题,回答等等的属性都写为这个蜘蛛的属性。代码如下

python# -*- coding: utf-8 -*-
import requests # requests作为我们的html客户端
from pyquery import PyQuery as Pq # pyquery来操作dom


class SegmentfaultQuestionSpider(object):

    def __init__(self, segmentfault_id): # 参数为在segmentfault上的id
        self.url = 'http://segmentfault.com/q/{0}'.format(segmentfault_id)
        self._dom = None # 弄个这个来缓存获取到的html内容,一个蜘蛛应该之访问一次

    @property
    def dom(self): # 获取html内容
        if not self._dom:
            document = requests.get(self.url)
            document.encoding = 'utf-8'
            self._dom = Pq(document.text)
        return self._dom

    @property 
    def title(self): # 让方法可以通过s.title的方式访问 可以少打对括号
        return self.dom('h1#questionTitle').text() # 关于选择器可以参考css selector或者jquery selector, 它们在pyquery下几乎都可以使用

    @property
    def content(self):
        return self.dom('.question.fmt').html() # 直接获取html 胆子就是大 以后再来过滤

    @property
    def answers(self):
        return list(answer.html() for answer in self.dom('.answer.fmt').items()) # 记住,Pq实例的items方法是很有用的

    @property
    def tags(self):
        return self.dom('ul.taglist--inline > li').text().split() # 获取tags,这里直接用text方法,再切分就行了。一般只要是文字内容,而且文字内容自己没有空格,逗号等,都可以这样弄,省事。

然后,再把玩一下升级后的蜘蛛。

python>>> from sfspider import spider
>>> s = spider.SegmentfaultQuestionSpider('1010000002542775')
>>> print s.title
>>> 微信JS—SDK嵌套选择图片和上传图片接口,实现一键上传图片,遇到问题
>>> print s.content
>>> # [故意省略] #
>>> for answer in s.answers
        print answer
>>> # [故意省略] #
>>> print '/'.join(s.tags)
>>> 微信js-sdk/python/微信开发/javascript

OK,现在我的蜘蛛玩起来更方便了。

2.2 编写分类爬虫

下面,我要写一个抓取标签页面的问题的爬虫。
代码如下, 注意下面的代码是添加在已有代码下面的, 和之前的最后一行之间 要有两个空行

pythonclass SegmentfaultTagSpider(object):

    def __init__(self, tag_name, page=1):
        self.url = 'http://segmentfault.com/t/%s?type=newest&page=%s' % (tag_name, page)
        self.tag_name = tag_name
        self.page = page
        self._dom = None

    @property
    def dom(self):
        if not self._dom:
            document = requests.get(self.url)
            document.encoding = 'utf-8'
            self._dom = Pq(document.text)
            self._dom.make_links_absolute(base_url="http://segmentfault.com/") # 相对链接变成绝对链接 爽
        return self._dom


    @property
    def questions(self):
        return [question.attr('href') for question in self.dom('h2.title > a').items()]

    @property
    def has_next_page(self): # 看看还有没有下一页,这个有必要
        return bool(self.dom('ul.pagination > li.next')) # 看看有木有下一页

    def next_page(self): # 把这个蜘蛛杀了, 产生一个新的蜘蛛 抓取下一页。 由于这个本来就是个动词,所以就不加@property了
        if self.has_next_page:
            self.__init__(tag_name=self.tag_name ,page=self.page+1)
        else:
            return None

现在可以两个蜘蛛一起把玩了,就不贴出详细把玩过程了。。。

python>>> from sfspider import spider
>>> s = spider.SegmentfaultTagSpider('微信')
>>> question1 = s.questions[0]
>>> question_spider = spider.SegmentfaultQuestionSpider(question1.split('/')[-1])
>>> # [故意省略] #

想做小偷站的,看到这里基本上就能搞出来了。 套个模板 加一个简单的脚本来接受和返回请求就行了。

未完待续。
下一篇,采集入库!

13 条评论
imlonghao · 2015年02月08日

我最近在做和你类似的事情,我目前在做:

采集Segmentfault,然后统计浏览数、收藏数等等的Top10...
目前在采集V2EX

我推荐你看看Pyspider这个爬虫框架,你会喜欢的。

https://esd.cc

回复

eric 作者 · 2015年02月09日

pyspider很不错

但是这个文章其实是写给我几个朋友和我小弟看的入门教程。。 所以 都是很简单 基础的东西

现在给他讲队列 异步 pipline啥的 他看不懂 但这些东西实践中必须得用

当然,同时希望能帮助其他的入门读者!

PS: 你的网站前端布局很好看 域名也很短。

回复

imlonghao · 2015年02月09日

加油,期待你下一部文章!

前端直接套的模板......我前端设计渣....
域名买了好几年了

回复

akagefly · 2015年04月07日

你好,我想请一下教如何把scrapy+django+数据库合在一起呢,后端爬虫爬好存入数据库,前端显示,作为一个入门的初学者,现在只会scrapy,跟一点点的django,现在不知道如何把抓出来的数据在前端显示

回复

eric 作者 · 2015年04月07日

个人感觉 scrapy 是一个很复杂的东西 用好不容易。

这个问题 应该可以用 pipline 解决 获取到一条数据之后 就用 pipline 执行相应的脚本 把信息转换成 Django 的 Model 的 instance 再 save 这个 instance

回复

akagefly · 2015年04月08日

就是用scrapy把数据抓紧数据库,再通过django前端显示出来,这个可行吗

回复

eric 作者 · 2015年04月09日

可以 就是之前回复的方案肯定是可以的

回复

苏生不惑 · 2015年07月19日

你的网站不错,我也常逛v2ex,不过收集的数据有点少

回复

imlonghao · 2015年07月19日

差不多的了,V2EX的帖子基本上都齐了/

回复

sashaqss · 2016年10月10日

您好,我是新手哈,在按照您的帖子学习中,运行spider.py的时候,提示importError: no module nadmed requests...这个requests是要另外自己再写吗?

回复

eric 作者 · 2016年10月10日

pip install requests. 也可以看视频 https://www.livecoding.tv/eri... 四分十五秒

回复

sashaqss · 2016年10月10日

多谢博主,居然在线,已经搞定:)

回复

sashaqss · 2016年10月28日

博主您好,请问采集到图片的文章,需要对图片怎么处理?直接保留原文的图片src会有什么影响吗?

回复

载入中...
eric eric

2k 声望

发布于专栏

eric

47 人关注