V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
cxa
V2EX  ›  Python

创建第一个 scrapy 工程-糗事百科

  •  
  •   cxa · 2018-11-01 15:51:12 +08:00 · 1973 次点击
    这是一个创建于 2249 天前的主题,其中的信息可能已经有所发展或是发生改变。

    创建第一个 scrapy 工程-糗事百科

    最近不少小伙伴儿,问我关于 scrapy 如何设置 headers 的问题,时间久了不怎么用,还真有的忘,全靠记忆去写了,为了方便大家参考,也方便我以后的查阅,这篇文章就诞生了。本章内容从实战出发让我们熟悉如何用 scrapy 写爬虫,本篇内容主要是实战,不讲述过多的理论性东西,因为讲多了我也不知道。😄

    明确目标

    首先,我们要明确我们的爬虫最终的目的是什么,这里我们要做的是爬取糗事百科的热门分类的前 10 页信息。包括发布者和内容,因为入门教程所以我们写的简单点主要是熟悉这个过程,这个如何入手呢?

    分析链接的变化

    一般我们会通过点击下一页,然后观察地址栏的信息来总结规律。 第一页也就是首页地址为: https://www.qiushibaike.com/ 我们点击下一页可以发现第二页的的连接为: https://www.qiushibaike.com/8hr/page/2/ 第三页: https://www.qiushibaike.com/8hr/page/3/ 。。。以此类推第十页的连接为: https://www.qiushibaike.com/8hr/page/10/ 由此我们发现规律,从第二页开始连接可以用 https://www.qiushibaike.com/8hr/page/页数 /来表示,有时候我比较喜欢试探,怎么说呢,我们知道这个规律是从第二页开始的,但是第一页是没有这个规律,但是我们不防试一试把第一页的 https://www.qiushibaike.com/改为 https://www.qiushibaike.com/8hr/page/1/。然后我们访问看看 ok 可以正常显示。 于是我们就确定了链接,也就是页数改为 1-10 就可以访问相应的页数了。

    安装 scrapy

    我们要确保正确安装好了 scrapy 针对 mac 和 linux 直接运行 pip 安装即可。

    pip install scrapy
    

    但是 windows 的坑就比较多了,关于 windows 的安装请参考我之前写的这篇文章 :https://www.cnblogs.com/c-x-a/p/8996716.html。这里就不多说了。 ###创建 scrapy 工程 好了下面我们开始创建工程首先我们使用 scrapy 的第一个命令 startproject, 使用方法:scrapy startproject xxx xxx 就是你的项目名,这里我们给我们的项目起名 qiushibaile。

     scrapy startproject qiushibaike
    

    然后我们会发现了多了一个文件名为 qiushibaike 的文件夹 然后我们通过命令创建一个事例工程 进入 qiushibaikle

    cd qiushibaike
    

    然后用下面 scrapy 的第二个命令 genspider 使用方法 scrapy genspider spider_name domain spider_name 就是爬虫的名字,每一个爬虫有一个名字这个名字是唯一的,后面运行的时候也是通过这个名字来运行的,下面的 qsbk 就是我们的爬虫名字,domain 指定爬虫的域也就是爬虫的范围。查找网页我们发现域名为

    scrapy genspider qsbk qiushibaike.com
    

    看到以下命令证明我们成功的创建了项目。

    Created spider 'qsbk' using template 'basic' in module:
      qiushibaike.spiders.qsbk
    

    ###开始编写 spider 文件 我们这里使用 pycharm 把我们的爬虫工程加载进来。 目录结构如下 (注意:run.py 是我后期自己添加的一个爬虫入口文件)

    修改 settings.py 文件

    无视 robots 协议,将

    ROBOTSTXT_OBEY = True
    

    改为

    ROBOTSTXT_OBEY = False
    

    修改 spider.py

    我们先来看看我们访问的网页源码对不对。 把 qsbk.py 改为

    # -*- coding: utf-8 -*-
    import scrapy
    
    
    class QsbkSpider(scrapy.Spider):
        name = 'qsbk'
        allowed_domains = ['qiushibaike.com']
        start_urls = ['http://qiushibaike.com/']#种子 url,列表类型表示支持多个
    
        def parse(self, response):
            print(response.text)#输出源码
    

    ###创建入口文件运行 在项目的根目录下创建一个 run.py 来运行我们的工程 run.py 的内容如下

    # -*- coding: utf-8 -*-
    # @Time : 2018/10/31 11:54 PM
    # @Author : cxa
    # @File : run.py.py
    # @Software: PyCharm
    from scrapy.cmdline import execute
    execute(['scrapy','crawl','qsbk'])
    

    运行以后我们发现一堆红色的信息,这些都是 scrapy 的日志内容,我们注意找是否有黑色字体的内容,一般 print 出来的内容是黑色字体和含有 error 的信息,以此了解我们的爬虫哪个地方出错了, 我们找到了 error 关键字,可以得知我们的爬虫出错了

    2018-11-01 00:08:38 [scrapy.downloadermiddlewares.retry] DEBUG: Retrying <GET https://www.qiushibaike.com/> (failed 1 times): [<twisted.python.failure.Failure twisted.internet.error.ConnectionDone: Connection was closed cleanly.>]
    2018-11-01 00:08:38 [scrapy.downloadermiddlewares.retry] DEBUG: Retrying <GET https://www.qiushibaike.com/> (failed 2 times): [<twisted.python.failure.Failure twisted.internet.error.ConnectionDone: Connection was closed cleanly.>]
    2018-11-01 00:08:38 [scrapy.downloadermiddlewares.retry] DEBUG: Gave up retrying <GET https://www.qiushibaike.com/> (failed 3 times): [<twisted.python.failure.Failure twisted.internet.error.ConnectionDone: Connection was closed cleanly.>]
    2018-11-01 00:08:39 [scrapy.core.scraper] ERROR: Error downloading <GET https://www.qiushibaike.com/>
    Traceback (most recent call last):
      File "/usr/local/lib/python3.7/site-packages/scrapy/core/downloader/middleware.py", line 43, in process_request
        defer.returnValue((yield download_func(request=request,spider=spider)))
    twisted.web._newclient.ResponseNeverReceived: [<twisted.python.failure.Failure twisted.internet.error.ConnectionDone: Connection was closed \
    

    按照提示可以知道链接被关闭访问失败了,这种情况下我们就被反爬了,常见的应对措施是修改 headers 头,下面我们就通过修改中间件来修改 headers。 ###修改中间件加入 headers 信息 首先修改 middlewares.py

    class UserAgentMiddleware(object):
    
        def __init__(self, user_agent_list):
            self.user_agent = user_agent_list
    
        @classmethod
        def from_crawler(cls, crawler, *args, **kwargs):
            # 获取配置文件中的 MY_USER_AGENT 字段
            middleware = cls(crawler.settings.get('MY_USER_AGENT'))
            return middleware
    
        def process_request(self, request, spider):
            # 随机选择一个 user-agent
            request.headers['user-agent'] = random.choice(self.user_agent)
    
    

    然后在 settings 启用我们的中间件和设定 MY_USER_AGENT 的值:

    MY_USER_AGENT = ["Mozilla/5.0+(Windows+NT+6.2;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/45.0.2454.101+Safari/537.36",
        "Mozilla/5.0+(Windows+NT+5.1)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/28.0.1500.95+Safari/537.36+SE+2.X+MetaSr+1.0",
        "Mozilla/5.0+(Windows+NT+6.1;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/50.0.2657.3+Safari/537.36"]
    
    DOWNLOADER_MIDDLEWARES = {
       'qiushibaike.middlewares.UserAgentMiddleware': 543,
    }
    

    然后我们再次运行,run.py 文件。 ###再次运行 我们成功获取了源码, 。然后我们就需要进行解析内容了。 ###解析网页中所需要的内容 因为这 10 页的结构是类似的我们就拿第一页为例: 在这里我们使用的解析方法为 xpath,通过 xpath 可以解析出我们需要的内容, 打开谷歌浏览器的开发者工具,首先通过 Elements 模块获取当前页所有内容的大概区域我们可以写这样的一个 xpath。

    "//div[@id='content-left']"
    

    然后我们发现一页 25 个内容,然后再去在每个内容里进行查找当前的标题和内容。 在 qsbk.py 文件的 parse 方法里加入这段内容

     content_left_node=response.xpath("//div[@id='content-left']") #确定发布区的节点区域
            div_node_list=content_left_node.xpath("./div")
            for div_node in  div_node_list:
                title_node=div_node.xpath(".//div[@class='author clearfix']/a[contains(@onclick,'web-list-author-text')]/h2/text()")
                content_node=div_node.xpath(".//div[@class='content']/span[1]")
                content=content_node.xpath('string(.)')
                print("发布者",title_node.extract_first().strip())
                print("发布内容",content.extract_first().strip())
    

    修改 scrapy 的日志显示等级方便查看

    前面运行过程中我们发现 scrapy 的日志信息非常的多,不容易找到我们想要的内容,这个时候我们可以通过修改 settings.py 文件通过修改 log 的等级,只显示指定类型的 log,打开 settings.py 我们加上下面的一句来设定 log 的等级为 error 也就是只有错误的时候才显示 scrapy 的 log 信息。

    LOG_LEVEL = "ERROR"
    

    然后再次运行,看到了我们我们需要的内容发布者和发布内容。 得到了这些我们现在只是打印了下,下面我们就来说如何存储 ###保存结果到 mongodb mongodb 是一个 key-value 型的数据库,使用起来简单,数据结构是键值对类型,在存储过程中如果表不存在就会创建一个新的表。 下面我们开始来存储我们的数据。

    构造数据

    因为我们需要接收一个键值对类型的数据,一般用 dict,所以我们将代码改成如下形式。qsbk.py 文件新增内容:

                item = {}
                item['name'] = name
                item['info'] = info
                yield item
    

    上面我们构造出了我们需要存储的数据,然后通过 yield 传递到存储部分, 下一步我们就要开始创建 mongo 连接的部分了。

    创建 mongo 连接文件

    pipelines.py 文件改为

    
    import pymongo
    from scrapy.conf import settings
    
    class MongoPipeline(object):
        def __init__(self):
            # 链接数据库
            self.client = pymongo.MongoClient(host=settings['MONGO_HOST'], port=settings['MONGO_PORT'])
            if settings.get('MINGO_USER'):
                   self.client.admin.authenticate(settings['MINGO_USER'], settings['MONGO_PSW'])
            self.db = self.client[settings['MONGO_DB']]  # 获得数据库
            self.coll = self.db[settings['MONGO_COLL']]  # 获得 collection
    
        def process_item(self, item, spider):
            postItem = dict(item)  # 把 item 转化成字典形式
            self.coll.insert(postItem)  # 向数据库插入一条记录
            return item 
    

    然后修改 settings.py,首先添加 mongo 的几个连接参数

    MONGO_HOST = "127.0.0.1"  # 主机 IP
    MONGO_PORT = 27017  # 端口号
    MONGO_DB = "spider_data"  # 库名
    MONGO_COLL = "qsbk"  # collection 名
    

    然后打开 pipe 通道

    ITEM_PIPELINES = {
       'qiushibaike.pipelines.MongoPipeline': 300,
    }
    

    运行查看数据

    我这里用的 adminmongo,打开 adminmogo 连接数据库,可以看到我们数据已经存在了。

    结语

    到此为止,我们一个简单完整的 scrapy 小项目就完成了。 为了方便查看代码已经上传 git: https://github.com/muzico425/qsbk.git 更多爬虫学习以及 python 技巧,请关注公众号:python 学习开发。

    Leigg
        1
    Leigg  
       2018-11-01 17:22:37 +08:00 via iPhone
    不怕折腾就好了,爬虫。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2492 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 15:35 · PVG 23:35 · LAX 07:35 · JFK 10:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.