python scrapy学习笔记

2020-01-06 22:25:10 浏览数 (1)

scrapy是python最有名的爬虫框架之一,可以很方便的进行web抓取,并且提供了很强的定制型。

一、安装scrapy

代码语言:javascript复制
# pip install scrapy

二、基本使用

1、初始化scrapy项目

代码语言:javascript复制
# scrapy startproject myscrapy

初始化完成后的目录结构

代码语言:javascript复制
# tree
.
├── myscrapy
│   ├── __init__.py
│   ├── items.py                      # 设置数据存储模板,用于结构化数据
│   ├── middlewares.py                # 中间件,相当于钩子,对爬去前后做预处理
│   ├── pipelines.py                  # 管道模块,处理spider模块分析好的数据,如保存入库等
│   ├── settings.py                   # 配置文件,如并发数,是否开启缓存
│   └── spiders
│       ├── __init__.py
│       └── myspider.py
└── scrapy.cfg                         # 项目的配置文件

一个例子爬取当当网的首页

代码语言:javascript复制
#!/usr/bin/python
#coding:utf-8

import scrapy

class DangDang(scrapy.Spider):
    # 必须定义
    name = "dangdang"
    # 初始urls
    start_urls = [ 
        "http://www.dangdang.com"
    ]   

    # 默认response处理函数
    def parse(self, response):      # 抓取start_urls页面,自动执行parse回调函数
        current_url = response.url  # 当前请求的URL
        body = response.body        # 请求的内容
        print '请求的URL: {}n请求的内容: {}'.format(current_url,body)

运行

代码语言:javascript复制
# scrapy crawl dangdang                # 方式1
# scrapy runspider dangdang.py         # 方式2

爬虫开始爬取start_urls定义的url,并输出到文件中,最后输出爬去报告,会输出爬取得统计结果

2、通过代码运行爬虫

每次进入控制台运行爬虫还是比较麻烦的,而且不好调试,我们可以通过CrawlerProcess通过代码运行爬虫,新建一个模块run.py

代码语言:javascript复制
#!/usr/bin/python
#coding:utf-8

from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from spiders.dangdang import DangDang

# 获取setting.py模块的设置
settings = get_project_settings()
process = CrawlerProcess(settings=settings)

# 添加spider,可以多个
process.crawl(DangDang)                                                                                                                                       

# 启动爬虫,阻塞知道爬取结束
process.start()

只需要执行python run.py就可以执行爬虫

三、Scrapy类

如上面的DangDang类,爬虫类继承自scrapy.Spider

1、常用属性

  • name:爬虫的名字,必须唯一(如果在控制台使用的话,必须配置)
  • start_urls:爬虫初始爬取的链接列表
  • parse:response结果处理函数
  • custom_settings:自定义配置,覆盖settings.py中的默认配置

2、常用方法

  • start_requests:启动爬虫的时候调用,默认是调用make_requests_from_url方法爬取start_urls的链接,可以在这个方法里面定制,如果重写了该方法,start_urls默认将不会被使用,可以在这个方法里面定制一些自定义的url,如登录,从数据库读取url等,本方法返回Request对象
  • make_requests_from_url:默认由start_requests调用,可以配置Request对象,返回Request对象
  • parse:response到达spider的时候默认调用,如果在Request对象配置了callback函数,则不会调用,parse方法可以迭代返回ItemRequest对象,如果返回Request对象,则会进行增量爬取

3、Request与Response对象

  每个请求都是一个Request对象,Request对象定义了请求的相关信息(url, method, headers, body, cookie, priority)和回调的相关信息(meta, callback, dont_filter, errback),通常由spider迭代返回

  其中meta相当于附加变量,可以在请求完成后通过response.meta访问请求完成后,会通过Response对象发送给spider处理,常用属性有(url, status, headers, body, request, meta)

四、选择器

  • 基本的选择器
  • 正则选择

1、基本的选择器

  1. //                    ## 子孙
  2. /                     # 孩子
  3. //div[@class='info'][@id='1']  # 属性选择器
  4. //div/img/@src            # div下所有img的src值
  5. //div/a[1]               # div下第一个<a>
  6. //div/a[1]/text()          # div下第一个<a>的值

例如

想要获取书名,可以写为: //ul[@class='list_aa listimg']/li//a/@title

查找方式

代码语言:javascript复制
# 方法1,即将被废弃的
from scrapy.selector import HtmlXPathSelector
hxs = HtmlXPathSelector(response)
items_HtmlXPathSelector = hxs.select('//ul[@class='list_aa listimg']/li//a/@title')
print(len(items_HtmlXPathSelector))

# 方法2
from scrapy.selector import Selector
items_Selector = Selector(response=response).xpath('//ul[@class='list_aa listimg']/li//a/@title')
print(len(items_Selector))

2、正则选择器

代码语言:javascript复制
<body>
    <li class="item-"><a href="link.html">first item</a></li>
    <li class="item-0"><a href="link1.html">first item</a></li>
    <li class="item-1"><a href="link2.html">second item</a></li>
</body>

书写方法://li[re:test(@class, "item-d*")]//@href

查找方式

代码语言:javascript复制
ret = Selector(response=response).xpath('//li[re:test(@class, "item-d*")]//@href').extract()
# re ---- 通过正则进行匹配
# test -- 匹配

五、使用scrapy爬取网站聊天记录和用户头像

代码语言:javascript复制
#!/usr/bin/python
#coding:utf-8

import scrapy
from scrapy.selector import Selector
import os
import requests

class NextSpider(scrapy.spiders.Spider):
    name = 'nextspider'
    start_urls = ["http://group.jobbole.com/27740/#comm-77724"]

    def parse(self,response):
        items_selector = Selector(response=response)
        items = items_selector.xpath('//ul[@class="cmnt-list"]/li')
#       print items
        for i in range(len(items)):
            srcs = items_selector.xpath('//ul[@class="cmnt-list"]/li[%d]//div[@class="cmnt-header"]/a/img/@src'%i).extract()
            names = items_selector.xpath('//ul[@class="cmnt-list"]/li[%d]//div[@class="cmnt-header"]/div/span[1]/a/text()'%i).extract()
            msgs = items_selector.xpath('//ul[@class="cmnt-list"]/li[%d]//div[@class="cmnt-body"]/p/text()'%i).extract()                                      
            if srcs and names and msgs:
                try:
                    img_url = srcs[0]
                    filename = names[0].encode('utf-8')
                    msg = ','.join([i.encode('utf-8') for i in msgs[1:]])
                    print '用户ID: {}n发表信息: {}'.format(filename,msg)
                    img_dir = 'imgs'
                    path = os.path.join(os.getcwd(),img_dir,filename '.png')
                    r = requests.get(img_url)
                    with open(path,'wb') as f:
                        for chunk in r.iter_content(chunk_size=1024):
                            if chunk:
                                f.write(chunk)
                                f.flush()
                        f.close()
                except Exception,e:
                    print '错误: {}'.format(e)

结果

代码语言:javascript复制
用户ID: 小编辑
发表信息: 恭喜!,说说你是怎么追到的。然后再打广告 :)
用户ID: 迷路的兔纸-->
发表信息: 你这是赤果果的炫耀
用户ID: sorry丶
发表信息: 10月份去九寨沟,在青旅里面遇到我的那个她。
... ...

图片

代码语言:javascript复制
# ls imgs/
lishenluo.png  sorry丶.png  寻找隐世快乐.png  小编辑.png  忠文.png  熊绎.png  连时光都吐了.png  迷路的兔纸-->.png

六、items.py中的Item类

初始化后默认的Item类

代码语言:javascript复制
import scrapy

class MyscrapyItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    pass

scrapy.Item的用法与python中的字典用法基本一样,只是做了一些安全限制,属性定义使用Field,这里只是进行了声明,而不是真正的属性,使用的时候通过键值对操作,不支持属性访问

七、Pipeline

spider负责爬虫的配置,item负责声明结构化数据,而对于数据的处理,在scrapy中使用管道的方式进行处理,只要注册过的管道都可以处理item数据(处理,过滤,保存)

示例:这里定义一个预处理管道PretreatmentPipeline.py,如果item的title为None,则设置为空字符串

代码语言:javascript复制
class PretreatmentPipeline(object):
    def process_item(self, item, spider):
        if item['msgs']:
            # 不让msgs为空
            item['msgs'] = ''
        return item

八、setting.py文件

setting.py文件中为我们提供了许多自带的功能,例如缓存、多线程等等,只需要修改配置即可

1、缓存

代码语言:javascript复制
# 打开缓存
HTTPCACHE_ENABLED = True

# 设置缓存过期时间(单位:秒)
#HTTPCACHE_EXPIRATION_SECS = 0

# 缓存路径(默认为:.scrapy/httpcache)
HTTPCACHE_DIR = 'httpcache'

# 忽略的状态码
HTTPCACHE_IGNORE_HTTP_CODES = []

# 缓存模式(文件缓存)
HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'

2、多线程

代码语言:javascript复制
# 默认Request并发数:32
CONCURRENT_REQUESTS = 32

# 默认每个域名的并发数:16
CONCURRENT_REQUESTS_PER_DOMAIN = 16

# 每个IP的最大并发数:0表示忽略
CONCURRENT_REQUESTS_PER_IP = 16

0 人点赞