scrapy爬取上海链家网35000条在租房信息并导入数据库

本文在有些需要解释说明的地方引用了知乎文章屌丝想买房……Scrapy入门教程

本篇教程中将按照下列五步实现标题所述目标:

1、创建一个Scrapy项目

本篇建议安装Anaconda3,Anaconda可以很方便地解决多版本python并存、切换以及各种第三方包安装问题。Anaconda利用工具/命令conda来进行package和environment的管理,并且已经包含了Python和相关的配套工具。

  • 1、新建项目: scrapy startproject lianjia
  • 2、切换目录:cd lianjia
  • 3、新建爬虫:scrapy genspider Ljia sh.lianjia.com/zufang

工程文件说明:
scrapy.cfg 记录项目的配置信息
items.py 存放爬取完数据的模板,用于结构化数据
pipelines 数据处理行为,比如结构化的数据,存放到数据库持久化等等
settings.py 配置文件,比如递归的层数、并发数,延迟下载等
spiders 真正干活的爬虫目录,对网页的数据清洗

2、定义提取的Item

Item是我们要爬取数据的模板,因此我们应该先编辑lianjia/lianjia下的items文件
观察我们要爬取的在租房示例图,首先想好你要爬取哪些关键信息

《scrapy爬取上海链家网35000条在租房信息并导入数据库》

在租房示例图

我定义的目标提取字段比较详细(也可以说比较啰嗦),字段含义参考代码注释


# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html

import scrapy


class LianjiaItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title = scrapy.Field()      #房间标题,例如:申金大厦,好楼层,钥匙在链家,链家好房
    roomType = scrapy.Field()   #房间类型,几室几厅
    roomName = scrapy.Field()   #房间名,例如:申金大厦
    roomPrice = scrapy.Field()  #价格,按月为单位
    roomStatus = scrapy.Field() #房间状态,例如:随时看房
    roomDate = scrapy.Field()   #房间上架日期,例如:2017.08.06
    areaB = scrapy.Field()      #区域   例如:浦东,黄浦
    street = scrapy.Field()     #街道,例如:距离5号线金平路站794米

3、编写爬取网站的spider并提取Item

网页解析

《scrapy爬取上海链家网35000条在租房信息并导入数据库》 租房信息
《scrapy爬取上海链家网35000条在租房信息并导入数据库》 网页源码

可以看到网页元素还是很好抽取的,但是我们要先做一些准备工作

  • 1、把setting.py里面的ROBOT协议尊守改为False,不修改爬不了任何数据).

《scrapy爬取上海链家网35000条在租房信息并导入数据库》 settings.py

  • 2、添加浏览器代理

《scrapy爬取上海链家网35000条在租房信息并导入数据库》 取消这块代码的注释并添加浏览器的代理

  • 3、取消注释

《scrapy爬取上海链家网35000条在租房信息并导入数据库》 image.png

以下代码使用xpath提取目标字段,xpath是抽取HTML元素最为便捷和快捷的方式,关于xpath的使用参考xpath语法


# -*- coding: utf-8 -*-
import scrapy
import re
from lianjia.items import LianjiaItem

class LjiaSpider(scrapy.Spider):
    name = 'Ljia'
    allowed_domains = ['https://sh.lianjia.com/zufang']
    start_urls = ['https://sh.lianjia.com/zufang']
    

    def parse(self, response):
        for i in response.xpath('.//li/div[@class="info-panel"]'):
            item = LianjiaItem()
            item['title'] = i.xpath('.//h2/a/@title').extract_first()
            item['roomName'] = i.xpath('.//div[@class="where"]/a/span/text()').extract_first()
            item['roomType'] = i.xpath('.//div[@class="where"]/span/text()').extract_first().rstrip(' &nbsp')
            roomDesc = i.xpath('.//div[@class="con"]').extract_first()
            item['roomPrice'] = i.xpath('.//div[@class="price"]/span/text()').extract_first()
            item['roomStatus'] = i.xpath('.//span[@class="anytime-ex"]/span/text()').extract_first()
            item['roomDate'] = i.xpath('.//div[@class="col-3"]/div[@class="price-pre"]/text()').extract_first().rstrip('7\n\t\t\t\t\t\t\t上架')
            item['areaB'] = str(i.xpath('.//div[@class="con"]/a/text()').extract()[0])
            item['street'] = i.xpath('.//span[@class="fang-subway-ex"]/span/text()').extract_first()
            yield item
        temp_url = response.xpath('//a[@gahref="results_next_page"]/@href').extract()[0]
        if temp_url:
            url = 'https://sh.lianjia.com' + temp_url
        yield scrapy.Request(url=url, callback=self.parse, dont_filter=True)

注释:extract_first()方法用来序列化抽取到的网页元素,dont_filter字段用于避免服务器把我们的爬虫url做重定向

4、编写Item PipeLine来存储提取到的Item(即数据)

/lianjia/lianjia/pipelines 文件

import pymysql 

class LianjiaPipeline(object):
    
    def __init__(self):
        self.conn = pymysql.connect(host='localhost', user='root', passwd='****', \
                                   db='***', charset='utf8')
        self.cur = self.conn.cursor()
        
    def process_item(self, item, spider):
        
        title = item.get('title', 'N/A')
        roomType = item.get('roomType', 'N/A')
        roomName = item.get('roomName', 'N/A')
        #roomSize = item.get('roomSize', 'N/A')
        #roomDesc = item.get('roomDesc', 'N/A')
        roomPrice = item.get('roomPrice', 'N/A')
        roomStatus = item.get('roomStatus', 'N/A')
        roomDate = item.get('roomDate', 'N/A')
        areaB = item.get('areaB', 'N/A')
        street = item.get('street', 'N/A')
        
        sql = 'insert into lianjia(title, roomType, roomName, roomPrice, \
                roomStatus, roomDate, areaB, street) values(%s, %s, %s, %s, %s, %s, %s, %s)'
        self.cur.execute(sql, (title, roomType, roomName, roomPrice, roomStatus, roomDate,areaB, street))
        self.conn.commit()
        #return item
        
    def close_spider(self, spider):
        self.cur.close()
        self.conn.close()

注释:
1、安装pymysql包:pip install pymysql
2、self.cur(游标对象)用于对数据表操作,self.conn(数据库对象)用于提交对数据库的操作

5、让爬虫动起来

上面的爬虫工程已经准备好了,现在可以运行一下等待结果了

  • 初步调试阶段:
    先注释掉pipelines文件中的sql执行语句,执行命令scrapy crawl Ljia -o house.csv做初步调试,不着急导入数据库,在终端观察爬虫运行情况,若出现报错则查看错误信息进行故障排查,若爬取成功则打开lianjia目录下面的house.csv文件查看爬取结果

《scrapy爬取上海链家网35000条在租房信息并导入数据库》 部分结果

  • 数据库导入阶段:
    若上面执行成功,则开始导入数据库,取消注释sql语句,执行命令scrapy crawl Ljia,在终端观察导入情况,若有报错,则排除问题,若成功写入, 则本次试验到此结束。若有数据库编码问题,可尝试自行解决。
    原文作者:山川之美_古来共谈
    原文地址: https://www.jianshu.com/p/277dec0b1843
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞