Scrapy(一) 入门

之前大部分的中间件都是在Docker中做的, 感觉Docker的确是牛逼, 隔离环境. 最近做一个爬虫的项目, 用到Scrapy, 最开始没有往Docker方面想, 之后有空需要研究下Docker如何安装Scrapy

安装

Scrapy是基于Python的爬虫框架, 需要先安装Python, 我的环境是Ubuntu 16.4默认条件下, Ubuntu安装了两个Python, Python2.7和Python3.5, 不知道这是什么操作

目前最新的Scrapy是基于Python3的, 如果在机器上有两个版本的Python, Scrapy会有冲突, 所以最开始先卸载Python2.7

sudo apt-get remove python

scrapy需要通过pip3进行安装, 注意这里是要pip3安装scrapy, 不是用pip, pip是基于python2的

安装pip3

可以使用如下命令安装pip3

sudo apt-get install python3-pip

如果安装过程中出现任何错误, 就多试几遍

查看pip3是否安装成功

pip3 –version

安装scrapy

pip3 install scrapy

安装过程中可能会报错, 并提示更新pip3

You are using pip version 8.1.1, however version 19.3.1 is available.

You should consider upgrading via the 'pip install --upgrade pip' command.

使用如下的命令更新pip3

pip3 install --upgrade pip

继续通过pip3 install scrapy, 出现下面的错误

这是因为将pip3更新为10.0.0后库里面的函数有所变动造成这个问题

nano /usr/bin/pip3

将原来的

from pip import main

if __name__ == '__main__':

    sys.exit(main())

改为

from pip import __main__

if __name__ == '__main__':

    sys.exit(__main__._main())

 

直到这里, 再通过pip3安装scrapy, 就基本上不会出错了

 

通过下面的命令验证scrapy的安装

pip3 list | grep Scrapy

案例

找了很多网上的教程, 发现有一个例子比较适合入门

scrapy startproject 工程名

通过这个命令, scrapy会帮忙建一个例子工程

items.py

这个文件定义了工程中会用到的类

import scrapy


class CrawlsHouseItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    pass
class DanKe(CrawlsHouseItem):
     # 房子名称
    host_name = scrapy.Field()
    # 租金
    price = scrapy.Field()
    # room list
    room_list = scrapy.Field()

pipelines.py文件定义了工程爬虫的输出

第一种方法是输出到文件

import io
import sys
reload(sys)
sys.setdefaultencoding('utf8')

class TutorialPipeline(object):
    def process_item(self, item, spider):
        return item
class CrawlsHousePipeline(object):
    def __init__(self):     
        self.file = io.open('danke.json', 'a', encoding='utf-8')

    def __del__(self):
        self.file.close()

    def process_item(self, item, spider):
        print(item, spider)       
        self.file.writelines(item['host_name']+'|'+item['price']+'|'+item['room_list'])
        return item

第二种方式是输出到数据库

import io
import pymysql
import sys
reload(sys)
sys.setdefaultencoding('utf8')


class TutorialPipeline(object):
    def process_item(self, item, spider):
        return item
class CrawlsHousePipeline(object):
    def __init__(self):

    	self.conn = pymysql.connect(
            host='192.168.25.132',
            port=3306,
            database='dk',
            user='root',
            password='123456',
            charset='utf8'
    	)
    	self.cursor = self.conn.cursor()

    def process_item(self, item, spider):
	sql = ("insert into danke(host_name,price,room_list)"
        	   "values (%s, %s, %s)")

   	item = dict(item)

    	data = [item['host_name'],
        	item['price'],
           	item['room_list']
               ]
   	self.cursor.execute(sql, data)
   	self.conn.commit()

    	return item

    def close_spider(self, spider):
        self.cursor.close()
        self.conn.close()

其他还有文件middlewares.py定义了工程中要用到的中间件

文件settings.py定义了工程的设置

真正的爬虫文件在spiders里面

class DankeSpider(scrapy.Spider):
    
    name = 'danke'
    
    allowed_domains = ['www.danke.com']
    
    start_urls = ['https://www.danke.com/room/bj']

    def parse(self, response):
        
        for href in response.xpath("//div[@class='r_lbx_cena']//a//@href").extract():
            
            yield scrapy.Request(href, self.parse_item)
        
        for next_href in response.xpath("//div[@class='page']//a//@href").extract():
            yield scrapy.Request(next_href)

    def parse_item(self, response):
        
        danke = DanKe()
        
        danke['host_name'] = response.xpath('//h1//text()').extract()[0]
        
        price = response.xpath('//div[@class="room-price-sale"]//text()').extract()[0]
        danke['price'] = price.replace(" ", "").replace("\n", "")
        
        room_list = []
        for room in response.xpath('//div[@class="room-list"]//text()').extract():
            room = room.replace(" ", "").replace("\n", "")
            if len(room) != 0:
                room_list.append(room)
        danke["room_list"] = ",".join(room_list)
        
        return danke

分页的抓取

分页的抓取是个比较头痛的部分, 最简单的情况是在代码中会直接有下一个页面的地址

<div class="page">
    <a href="https://www.danke.com/room/bj?page=1"  class="on">1</a>
    <a href="https://www.danke.com/room/bj?page=2"  class="">2</a>
    <a href="https://www.danke.com/room/bj?page=3"  class="">3</a>
    <a href="https://www.danke.com/room/bj?page=4"  class="">4</a>
    <a href="https://www.danke.com/room/bj?page=5"  class="">5</a>
    <a href="https://www.danke.com/room/bj?page=2"> > </a>
</div>

这样的话, 可以直接在scrapy进行循环获取

for next_href in response.xpath("//div[@class='page']//a//@href").extract():
            yield scrapy.Request(next_href)

但是大部分页面的分页都是通过js控制的, 并不会有直接的链接, 这个时候如果只是单一系列的页面, 可以定义全局的变量, 然后拼页面的链接实现

 

如果是一系列的页面, 不太容易可以给全局变量进行清零, 所以这种方式不合适

 

另外一种比较灵活的办法, 分页的控件都会有下一页的按钮, 基本上都会传入下一页的页码, 这时候通过解析锚点得到下一页的页码, 再拼页面的链接实现下一页的抓取

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值