用 Scrapy 抓取某家的楼盘信息

2023-10-24 16:50

本文主要是介绍用 Scrapy 抓取某家的楼盘信息,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近想爬点东西,又不想造轮子,就用上了scrapy,顺便记录下自己踩过的坑和都做了些什么。


使用的软件版本:

Python 3.5.x

ipython 5.1.x

scrapy 1.4


准备阶段(在动手写之前,一定要先观察好标签位置!):

这里使用Firefox的插件firebug对进行页面标签确定:

该页面有好几个楼盘信息,所以在看到上面的<li>标签后,应该再找一下它的父节点<ul>:

这些就是想要抓的新楼盘列表,id也说明了该ul列表的作用。在子节点<li>中继续寻找到自己想要的信息,找完差不多就可以开始爬虫的编写了。


编写阶段:

scrapy startproject house(项目名字,我这里用了house)
其文件夹内容:

house
├── house
│   ├── __init__.py
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── __pycache__
│   ├── settings.py
│   └── spiders
│       ├── __init__.py
│       └── __pycache__
└── scrapy.cfg


在items.py 文件里添加 item(保存爬取到的数据的容器;其使用方法和python字典类似)

import scrapyclass HouseItem(scrapy.Item):city = scrapy.Field()title = scrapy.Field()region = scrapy.Field()room = scrapy.Field()area = scrapy.Field()average = scrapy.Field()other = scrapy.Field()
上面我加了城市,楼盘名字,位置,房间,面积,均价和其他,具体可以看自己需求定义。


house/spiders/ 目录下添加house_spider.py ,并添加以下内容:

import scrapy
# 从上一层目录导入items.py的HouseItem类
from house.items import HouseItemclass HouseSpider(scrapy.Spider):# 爬虫名,不能冲突name = 'house'# 请求开始def start_requests(self):urls = ['http://bj.fang.lianjia.com/loupan/']# 对urls列表进行迭代请求for url in urls:yield scrapy.Request(url=url, callback=self.parse)    # 对响应的数据进行有选择性的抓取def parse(self, response):for house in response.xpath('//ul[contains(@id, "house-lst")]/li'):item = HouseItem()item['title'] = house.xpath('.//h2').xpath('.//a[contains(@data-el, "xinfang")]/text()').extract()item['region'] = house.xpath('.//span[contains(@class, "region")]/text()').extract()item['room'] = house.xpath('.//div[contains(@class, "area")]/text()').re('\S*\w')item['area'] = house.xpath('.//div[contains(@class, "area")]/span/text()').extract()item['other'] = list(set(house.xpath('.//div[contains(@class, "other")]').xpath('.//span/text()').extract() + house.xpath('.//div[contains(@class, "type")]').xpath('.//span/text()').extract()))item['average'] = house.xpath('.//div[contains(@class, "average")]').re('.*\s*(\w*)\s.*>(.\d*).*\s*(\w.*)')yield item

PS:正则写得有点丑,以后再修改,先用着。

PPS:scrapy shell 网址,用来调试还不错,不过建议先装ipython,能补全关键字。

留给自己:这里的选择器一开始用得不对,卡了很久,总是多了些空元素[ ],后来重新观察web页面元素,才发现自己写得不对,改成上面这样才好了,所以准备阶段很重要!


做到这里,就可以运行爬虫了:

scrapy crawl house(上面定义的爬虫名)

不过  这样没有保存下数据,可以使用-o输出json格式数据

scrapy crawl house -o data.json
当然还有其他格式的输出,可以看官网: https://docs.scrapy.org/en/latest/topics/feed-exports.html


只有第一页明显不够用,如何抓下一页呢?

同样,先进行下一页标签的获取:

本来很简单的,直接用 response.xpath("//a[contains(., '下一页')]//@href").extract_first() 应该提取到这个标签的href,不过不行,一番折腾也没发现有其他直接获取到该下一页标签的方法,没办法只能用它的父节点:

<div class="page-box house-lst-page-box" comp-module="page" data-xftrack="10139" page-url="/loupan/pg{page}/" page-data="{"totalPage":26,"curPage":1}">

这个父节点的page-data属性中包括了总页数和当前页,所以在当页基础上加1就可以到达下一页:
next_page = '/loupan/pg' + str(int(page[1]) + 1)


而且还要用总页数和当前页比较,来确定是最后一页,所以加上这些的house_spider.py 代码如下:

import scrapy
# 从上一层目录导入items.py的HouseItem类
from house.items import HouseItemclass HouseSpider(scrapy.Spider):# 爬虫名,不能冲突name = 'house'# 请求开始def start_requests(self):urls = ['http://bj.fang.lianjia.com/loupan/']# 对urls列表进行迭代请求for url in urls:yield scrapy.Request(url=url, callback=self.parse)    # 对响应的数据进行有选择性的抓取def parse(self, response):for house in response.xpath('//ul[contains(@id, "house-lst")]/li'):item = HouseItem()item['title'] = house.xpath('.//h2').xpath('.//a[contains(@data-el, "xinfang")]/text()').extract()item['region'] = house.xpath('.//span[contains(@class, "region")]/text()').extract()item['room'] = house.xpath('.//div[contains(@class, "area")]/text()').re('\S*\w')item['area'] = house.xpath('.//div[contains(@class, "area")]/span/text()').extract()item['other'] = list(set(house.xpath('.//div[contains(@class, "other")]').xpath('.//span/text()').extract() + house.xpath('.//div[contains(@class, "type")]').xpath('.//span/text()').extract()))item['average'] = house.xpath('.//div[contains(@class, "average")]').re('.*\s*(\w*)\s.*>(.\d*).*\s*(\w.*)')yield item# 对属性中的总页数和当前页进行提取page = response.xpath('//div[contains(@class, "page-box")]/@page-data').re('totalPage":(\w*).*:(\w*)')# 最后一页的页码和总页数一致if page[0] != page[1]:next_page = '/loupan/pg' + str(int(page[1]) + 1)yield scrapy.Request(response.urljoin(next_page))

再运行一下爬虫,已经能抓到很多页的数据了。不过还是有些问题,有些楼盘信息出现缺失,这是怎么回事呢?

{"title": ["中骏西山天璟"], "room": ["3居/2居"], "area": ["建面 102~155m²"], "other": ["五证齐全", "在售", "低密度", "住宅"], "region": ["门头沟-龙泉镇城子大街东侧"], "average": ["均价", "67000", "元/平"]}
{"title": ["炫立方"], "room": [], "area": [], "other": ["五证齐全", "在售", "商铺"], "region": ["顺义-南法信顺平路与南焦路交汇处向南50米路东"], "average": ["均价", "43000", "元/平"]}

找到对应的楼盘看了下缺失信息对应的标签,发现这些标签原本就没数据:

<div class="area"><span></span></div>

就是和爬虫本身并没有关系,所以后续要在pipelines.py 中添加过滤函数,对这些缺失信息的楼盘进行删除。

官方文档:https://docs.scrapy.org/en/latest/topics/item-pipeline.html


在数据比较少的情况,可以用json文件保存。但是数据多了json已经不够用了,这时候需要将它们保存到数据库中。

这里就用NoSQL非关系型的MongoDB来保存。

首先在settings.py 中添加:

MONGODB_HOST = 'localhost'
MONGODB_PORT = 27017
MONGODB_DB = 'house'
MONGODB_COLLECTION = 'lianjia'

然后去掉ITEM_PIPELINES 那行的注释,并添加在pipelines.py 中自定义的类MongoDBPipeline:

ITEM_PIPELINES = {'house.pipelines.HousePipeline': 200,'house.pipelines.MongoDBPipeline': 300,
}

在pipelines.py 中添加类MongoDBPipeline:

class MongoDBPipeline(object):def open_spider(self, spider):# 连接mongodb数据库self.client = pymongo.MongoClient(host=settings['MONGODB_HOST'], port=settings['MONGODB_PORT'])# 设置数据库self.db = self.client[settings['MONGODB_DB']]# 设置文档self.collection = self.db[settings['MONGODB_COLLECTION']]def process_item(self, item, spider):# 向文档中插入一条数据self.collection.insert_one(dict(item))return itemdef close_spider(self, spider):# 数据库连接关闭self.client.close()

 

这章就完成了对一个地区的新楼盘信息的抓取,以及存储。如果想抓其他地区的,只要在urls列表中添加其他地区的代码即可。

代码(与本文有些差别):Github

这篇关于用 Scrapy 抓取某家的楼盘信息的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/276523

相关文章

C#实现系统信息监控与获取功能

《C#实现系统信息监控与获取功能》在C#开发的众多应用场景中,获取系统信息以及监控用户操作有着广泛的用途,比如在系统性能优化工具中,需要实时读取CPU、GPU资源信息,本文将详细介绍如何使用C#来实现... 目录前言一、C# 监控键盘1. 原理与实现思路2. 代码实现二、读取 CPU、GPU 资源信息1.

在C#中获取端口号与系统信息的高效实践

《在C#中获取端口号与系统信息的高效实践》在现代软件开发中,尤其是系统管理、运维、监控和性能优化等场景中,了解计算机硬件和网络的状态至关重要,C#作为一种广泛应用的编程语言,提供了丰富的API来帮助开... 目录引言1. 获取端口号信息1.1 获取活动的 TCP 和 UDP 连接说明:应用场景:2. 获取硬

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

C#实现获取电脑中的端口号和硬件信息

《C#实现获取电脑中的端口号和硬件信息》这篇文章主要为大家详细介绍了C#实现获取电脑中的端口号和硬件信息的相关方法,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 我们经常在使用一个串口软件的时候,发现软件中的端口号并不是普通的COM1,而是带有硬件信息的。那么如果我们使用C#编写软件时候,如

通过C#获取PDF中指定文本或所有文本的字体信息

《通过C#获取PDF中指定文本或所有文本的字体信息》在设计和出版行业中,字体的选择和使用对最终作品的质量有着重要影响,然而,有时我们可能会遇到包含未知字体的PDF文件,这使得我们无法准确地复制或修改文... 目录引言C# 获取PDF中指定文本的字体信息C# 获取PDF文档中用到的所有字体信息引言在设计和出

C#读取本地网络配置信息全攻略分享

《C#读取本地网络配置信息全攻略分享》在当今数字化时代,网络已深度融入我们生活与工作的方方面面,对于软件开发而言,掌握本地计算机的网络配置信息显得尤为关键,而在C#编程的世界里,我们又该如何巧妙地读取... 目录一、引言二、C# 读取本地网络配置信息的基础准备2.1 引入关键命名空间2.2 理解核心类与方法

使用Python检查CPU型号并弹出警告信息

《使用Python检查CPU型号并弹出警告信息》本教程将指导你如何编写一个Python程序,该程序能够在启动时检查计算机的CPU型号,如果检测到CPU型号包含“I3”,则会弹出一个警告窗口,感兴趣的小... 目录教程目标方法一所需库步骤一:安装所需库步骤二:编写python程序步骤三:运行程序注意事项方法二

PostgreSQL如何查询表结构和索引信息

《PostgreSQL如何查询表结构和索引信息》文章介绍了在PostgreSQL中查询表结构和索引信息的几种方法,包括使用`d`元命令、系统数据字典查询以及使用可视化工具DBeaver... 目录前言使用\d元命令查看表字段信息和索引信息通过系统数据字典查询表结构通过系统数据字典查询索引信息查询所有的表名可

业务中14个需要进行A/B测试的时刻[信息图]

在本指南中,我们将全面了解有关 A/B测试 的所有内容。 我们将介绍不同类型的A/B测试,如何有效地规划和启动测试,如何评估测试是否成功,您应该关注哪些指标,多年来我们发现的常见错误等等。 什么是A/B测试? A/B测试(有时称为“分割测试”)是一种实验类型,其中您创建两种或多种内容变体——如登录页面、电子邮件或广告——并将它们显示给不同的受众群体,以查看哪一种效果最好。 本质上,A/B测

【北交大信息所AI-Max2】使用方法

BJTU信息所集群AI_MAX2使用方法 使用的前提是预约到相应的算力卡,拥有登录权限的账号密码,一般为导师组共用一个。 有浏览器、ssh工具就可以。 1.新建集群Terminal 浏览器登陆10.126.62.75 (如果是1集群把75改成66) 交互式开发 执行器选Terminal 密码随便设一个(需记住) 工作空间:私有数据、全部文件 加速器选GeForce_RTX_2080_Ti