Scrapy实例————爬取链家二手房数据,并处理后存入csv


目标

通过Scrapy爬取链家二手房数据,地址 https://bj.lianjia.com/ershoufang/ ,并对爬取到的数据进行处理,存储到csv文件中。

环境

博主是在Windows平台使用PyCharm基于Python 3.7Scrapy 2.0.1编写爬虫,不赘述环境配置了。

建立项目

右键Scrapy文件夹,选择在终端中打开

在终端中输入scrapy startproject lianjiaershou,其中lianjiaershou为项目名。

更改items.py

import scrapy

# 为增强可读性,直接以中文作为变量名
class MyItem(scrapy.Item):
    标题 = scrapy.Field()
    小区 = scrapy.Field()
    区域 = scrapy.Field()
    户型_室 = scrapy.Field()
    户型_厅 = scrapy.Field()
    面积 = scrapy.Field()
    朝向 = scrapy.Field()
    装修 = scrapy.Field()
    楼层 = scrapy.Field()
    建成年份 = scrapy.Field()
    建筑结构 = scrapy.Field()
    关注人数 = scrapy.Field()
    已发布日 = scrapy.Field()
    总价 = scrapy.Field()
    单价 = scrapy.Field()
    满二 = scrapy.Field()
    满五 = scrapy.Field()
    近地铁 = scrapy.Field()

分析网页

复制三个标题的xpath,不难找到规律:

/html/body/div[4]/div[1]/ul/li[1]/div[1]/div[1]/a
/html/body/div[4]/div[1]/ul/li[2]/div[1]/div[1]/a
/html/body/div[4]/div[1]/ul/li[3]/div[1]/div[1]/a

只需迭代爬取每个li区块即可。

新建并更改spider.py

spider文件夹中新建spider.py,并键入:

# 为了方便更改,设置全局变量
page = 100  # 爬取页数
area = "haidian"  # 爬取城区

import scrapy
from lianjiaershou.items import MyItem
class mySpider(scrapy.spiders.Spider):
    name = "lianjiaershou"
    allowed_domains = ["bj.lianjia.com"]
    start_urls = []
    # 依次将第1页到第page页放入开始连接队列
    for i in range(1 , page+1):
        start_urls.append("https://bj.lianjia.com/ershoufang/{}/pg{}/".format(area, i))
    # 如果你希望一次爬取多个城区,可以使用如下语句
    '''
    areas = ['dongcheng', 'xicheng', 'haidian', 'chaoyang']
    for each in areas:
        for i in range(1, page+1):
            start_urls.append("https://bj.lianjia.com/ershoufang/{}/pg{}/".format(each, i))
    '''


    def parse(self, response):
        item = MyItem ()
        for each in response.xpath("/html/body/div[4]/div[1]/ul/*"):
            # item['城区'] = response.url.split('/')[-3]  # 如果你一次性爬取了多个城区,可以使用该语句
            item['标题'] = each.xpath("div/div[1]/a/text()").extract()[0]
            item['小区'] = each.xpath("div/div[2]/div/a[1]/text()").extract()[0]
            item['区域'] = each.xpath("div/div[2]/div/a[2]/text()").extract()[0]
            # 由于信息以字符串形式存在,并以' | '分隔,故创建临时变量,分割字符串,存为列表
            temp = each.xpath("div/div[3]/div/text()").extract()[0].split(' | ')
            # temp[0]的格式是n室m厅
            item['户型_室'] = temp[0][0]
            item['户型_厅'] = temp[0][-2]
            item['面积'] = temp[1][:-2]  # 去除汉字'平米'
            item['朝向'] = temp[2]
            item['装修'] = temp[3]
            item['楼层'] = temp[4]
            item['建成年份'] = temp[5][:-2]  # 去除汉字'年建'
            if len(temp) <= 6 or temp[6]=='暂无数据':
                item['建筑结构'] = 'N/A'
            else:
                item['建筑结构'] = temp[6]
            temp = each.xpath("div/div[4]/text()").extract()[0].split(' / ')
            item['关注人数'] = temp[0][:-3]
            # 日期格式可分为 n天以前前 n个月以前 一年前
            if temp[1][1] == '天':
                item['已发布日'] = int(temp[1][0])
            elif temp[1][1] == '个':
                item['已发布日'] = int(temp[1][0]) * 30
            else:
                item['已发布日'] = 360
            if each.xpath("div/div[5]/span[@class='taxfree']/text()").extract():
                item['满五'] = True
            else:
                item['满五'] = False
            if each.xpath("div/div[5]/span[@class='five']/text()").extract():
                item['满二'] = True
            else:
                item['满二'] = False
            if each.xpath("div/div[5]/span[@class='subway']/text()").extract():
                item['近地铁'] = True
            else:
                item['近地铁'] = False
            item['总价'] = each.xpath("div/div[6]/div[1]/span/text()").extract()[0]
            item['单价'] = each.xpath("div/div[6]/div[2]/span/text()").extract()[0][2:-4]  # 去除汉字'单价*元/平米'
            yield item

更改setting.py

BOT_NAME = 'lianjiaershou'

SPIDER_MODULES = ['lianjiaershou.spiders']
NEWSPIDER_MODULE = 'lianjiaershou.spiders'
# 不遵守机器人协议
ROBOTSTXT_OBEY = False
# 客户端伪装
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36'
# 防止ip被封,每页延迟1s爬取
DOWNLOAD_DELAY = 1

新建begin.py


在项目文件夹中新建begin.py,内容为:

from scrapy import cmdline
from lianjiaershou.spiders import spider  # 用于从linajiaershou/spiders/spider.py读取area变量
import os
if os.path.exists("data/data_{}.csv".format(spider.area)):
    os.remove("data/data_{}.csv".format(spider.area))  # 为了防止文件已存在导致索引和数据重复,先删除将要生成的文件
cmdline.execute("scrapy crawl lianjiaershou -o data/data_{}.csv -t csv".format(spider.area).split())
# 如果你不想以spider.py中area命名文件,请参考以下
'''
if os.path.exists("data/data.csv"):
    os.remove("data/data.csv")  # 为了防止文件已存在导致索引和数据重复,先删除将要生成的文件
cmdline.execute("scrapy crawl lianjiaershou -o data/data.csv -t csv".split())
'''

其中lianjiaershou为爬虫名(无须与项目名相同)。目的是为了方便运行爬虫。(忽略图中代码内容,只看项目结构就好,只是博主懒得再重新截图了)
这里直接使用scrapy命令保存到csv,pipelines.py保持默认即可。

运行爬虫

运行begin.py,成功爬取到数据。这里只列举部分。

关注人数,区域,单价,小区,已发布日,建成年份,建筑结构,总价,户型_厅,户型_室,朝向,标题,楼层,满二,满五,装修,近地铁,面积
119,四季青,106072,美丽园 ,360,2000,板楼,1160,1,2,南 北,美丽园小区一层带花园两居室,位置安静临水系,底层(共6层),False,True,简装,True,109.36
147,厂洼,99173,厂洼小区 ,360,1990,塔楼,719,1,3,西南,厂洼小区  西南向三居 带电梯 采光好,中楼层(共20层),True,False,简装,True,72.5
72,甘家口,93214,国兴家园 ,360,2000,塔楼,1390,1,3,东南,东南向三居室,户型方正,随时可看,低楼层(共24层),False,True,简装,True,149.12
149,玉泉路,61400,玉海园二里 ,360,1998,板塔结合,610,2,2,西北,海淀玉泉路 玉海园电梯两居室 满五年商品房 诚意出售,高楼层(共11层),False,True,简装,True,99.35
197,田村,78543,雅世合金公寓 ,360,2011,板塔结合,709,1,2,东 西,雅世合金 十大科技系统居住舒适度高 户型好,中楼层(共9层),False,True,精装,True,90.27

备注

由于通过scrapy命令行写csv是a模式且无法更改,所以如果多次运行会导致索引和数据重复。该问题已解决,已经修改代码。
也可通过pipelines.py实现,本文不再赘述。


文章作者: BoyInTheSun
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 BoyInTheSun !
 上一篇
matplotlib实例————绘制链家二手房数据箱型图 matplotlib实例————绘制链家二手房数据箱型图
目标利用matplotlib(v3.2),在链家二手房平台爬取自己家乡或者北京的3~4个区域的二手房信息,处理后保存为data.csv,并探究不同的区二手房总价数据。 求解爬取并处理数据参见 https://boyinthesun.cn/p
2020-05-15
下一篇 
pyecharts实例————绘制中国各省高考人数和大学数量可视化地图 pyecharts实例————绘制中国各省高考人数和大学数量可视化地图
目标通过提供的csv文件,利用pyecharts(v1.7),在中国地图上展示各省的高考人数和大学数量。 分析csv文件由于数据较少,直接在此列出 ,高考人数,,大学数量, 省/市,2017年,2016年,211&985大学数量,公办本科大
2020-05-12
  目录