在数据获取和处理方面,网络爬虫是一种强大的工具。本教程将向您展示如何使用 Python 的 Scrapy 网络爬虫框架从 5i5j 网站上提取房产数据,并将提取的信息存储到 MongoDB 数据库中。
确保您的计算机上安装了 Python。您可以在Python官方网站上下载并安装最新版本的 Python。
在安装 Python 时,通常会一并安装 pip,它是 Python 包管理工具。但如果您的 Python 版本较旧或者没有安装 pip,请根据您的操作系统安装 pip。
使用 pip 安装 Scrapy。在命令行中执行以下命令:
pip install scrapy
这将安装最新版本的 Scrapy 爬虫框架。
要将爬取到的数据存储到 MongoDB 中,需要安装 pymongo 这个 Python MongoDB 客户端库。在命令行中执行以下命令:
pip install pymongo
如果您尚未安装 MongoDB 数据库,您可以从MongoDB官方网站下载适用于您操作系统的版本并进行安装。
确保您已经在本地启动了 MongoDB 服务。然后使用以下命令连接到 MongoDB,并创建一个数据库和集合来存储爬取到的数据:
mongo
use pachong # 创建名为 pachong 的数据库
db.createCollection("pachong") # 在 pachong 数据库中创建名为 pachong 的集合
scrapy startproject pachong2 #创建pachong2项目
cd pachong2 #移动到该pachong2目录下
这里以创建“pachong3”为例
scrapy genspider woaiwojia bj.5i5j.com
#woaiwojia为爬虫文件名,后续一直使用该文件名
#bj.5i5j.com为网站domain(域名)
最终得到以下文件目录
spiders下的woaiwojia.py即为主体爬虫文件
现在您已经设置好了 Python、Scrapy、pymongo 和 MongoDB,可以开始编写和运行 Scrapy Spider 来爬取数据并将其存储到 MongoDB 数据库中了。
观察一下目标链接
进入目标网站观察链接地址
目标链接=“网站首页前缀”+“href中的内容”
即“https://bj.5i5j.com”+“/ershoufang/503007737.html”
得到规则后,可以开始编写代码。
这里选择的是selector定位,
def parse(self, response):
base_url = 'https://bj.5i5j.com' # 基础URL
# 定位具有特定类名的元素并提取链接
for element in response.css('.listTit'):
relative_link = element.css('a::attr(href)').get()
if relative_link:
# 构建完整的链接
full_link = base_url + relative_link
yield scrapy.Request(full_link, callback=self.parse_house)
# 获取下一页链接
next_page = response.css('a.cPage::attr(href)').get()
if next_page:
yield response.follow(next_page, callback=self.parse)
价格:
这里使用xpath定位
经纪人姓名,以及房源信息和名称均使用xpath进行定位,方法同上,如有其他需要爬取的信息,采取的方法类似,不再赘述。
具体实现代码:
def parse_house(self, response):
house_name = response.xpath('/html/body/div[6]/div[1]/div[1]/h1/text()').get()
price = response.xpath('/html/body/div[6]/div[2]/div[2]/div[1]/div[1]/div[1]/span/text()').get()
agent_name = response.xpath('/html/body/div[6]/div[2]/div[2]/div[3]/ul/li[2]/h3/a/text()').get()
house_link = response.url # 获取当前页面的链接
# 提取基础属性信息和交易属性信息...
# 提取基础属性信息
basic_attributes = {
'房屋户型': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="房屋户型"]/span/text()').get(),
'所在楼层': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="所在楼层"]/span/text()').get(),
'建筑面积': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="建筑面积"]/span/text()').get(),
'户型结构': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="户型结构"]/span/text()').get(),
'套内面积': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="套内面积"]/span/text()').get(),
'建筑类型': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="建筑类型"]/span/text()').get(),
'房屋朝向': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="房屋朝向"]/span/text()').get(),
'建筑结构': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="建筑结构"]/span/text()').get(),
'装修情况': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="装修情况"]/span/text()').get(),
'供暖方式': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="供暖方式"]/span/text()').get(),
'配备电梯': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="配备电梯"]/span/text()').get()
}
# 提取交易属性信息
transaction_attributes = {
'发布时间': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="发布时间"]/span/text()').get(),
'建成年代': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="建成年代"]/span[1]/text()').get(),
'产权性质': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="产权性质"]/span/text()').get(),
'规划用途': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="规划用途"]/span/text()').get(),
'上次交易': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="上次交易"]/span/text()').get(),
'购房年限': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="购房年限"]/span/text()').get(),
'共有情况': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="共有情况"]/span/text()').get(),
'抵押情况': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="抵押情况"]/span/text()').get(),
'房本备件': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="房本备件"]/span/text()').get()
}
mongodb配置信息
# 添加MongoDB配置
mongo_uri = 'mongodb://localhost:27017/' # MongoDB URI
mongo_db = 'pachong' # MongoDB数据库名称
mongo_collection = 'pachong' # MongoDB集合名称
写入json与数据库
# 将数据存储到json文件
yield {
'房屋名称': house_name.strip() if house_name else None,
'价格': price.strip() if price else None,
'经纪人姓名': agent_name.strip() if agent_name else None,
'房屋链接': house_link, # 将房屋链接包含在输出中
'基础属性信息': basic_attributes,
'交易属性信息': transaction_attributes
}
# 将数据存储到MongoDB
data_to_insert = {
'房屋名称': house_name.strip() if house_name else None,
'价格': price.strip() if price else None,
'经纪人姓名': agent_name.strip() if agent_name else None,
'房屋链接': house_link, # 保留房屋链接在输出中
'基础属性信息': basic_attributes,
'交易属性信息': transaction_attributes
# 根据需要添加其他字段
}
# 插入数据到MongoDB集合中
self.collection.insert_one(data_to_insert)
yield data_to_insert
custom_settings = {
'DEFAULT_REQUEST_HEADERS': {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36',
'Referer': 'https://bj.5i5j.com/'
},
'FEEDS': {
'items.json': {
'format': 'json',
'overwrite': True,
'indent': 4,
'fields': None,
'include_links': True,
}
}
}
pipelines.py
import pymongo
from scrapy.exceptions import DropItem
class MongoDBPipeline:
collection_name = 'pachong' # 更新为您的MongoDB集合名称
def __init__(self, mongo_uri, mongo_db):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db
@classmethod
def from_crawler(cls, crawler):
return cls(
mongo_uri=crawler.settings.get('MONGO_URI'),
mongo_db=crawler.settings.get('MONGO_DATABASE')
)
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]
def close_spider(self, spider):
self.client.close()
def process_item(self, item, spider):
# 转换价格字段为实际的数字
if '价格' in item:
price = item['价格']
try:
# 判断价格是否包含"万"单位
if '万' in price:
# 去除价格中的"万"并转换为实际数字
price_value = float(price.replace('万', ''))
# 将价格乘以一万,得到实际的价格
item['价格'] = int(price_value * 10000)
else:
# 如果价格没有单位"万",将其转换为整数
item['价格'] = int(float(price))
except ValueError:
raise DropItem("Invalid price format in %s" % item)
if item.get('价格') is None:
raise DropItem("Missing price in %s" % item)
# 插入数据到 MongoDB
self.db[self.collection_name].insert_one(dict(item))
return item
settings.py
BOT_NAME = "pachong2"
SPIDER_MODULES = ["pachong2.spiders"]
NEWSPIDER_MODULE = "pachong2.spiders"
ROBOTSTXT_OBEY = True
REQUEST_FINGERPRINTER_IMPLEMENTATION = "2.7"
TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"
FEED_EXPORT_ENCODING = "utf-8"
MONGO_URI = 'mongodb://localhost:27017/' # 更新为您的MongoDB URI
MONGO_DATABASE = 'pachong' # 更新为您的MongoDB数据库名称
以下是完整代码,让我们看一下示例代码,它展示了如何创建一个 Scrapy Spider 来爬取 5i5j 网站上的房产数据,并将数据存储到 MongoDB 中。
import scrapy
import pymongo
class Fivei5jSpider(scrapy.Spider):
name = 'woaiwojia'
allowed_domains = ['bj.5i5j.com']
start_urls = ['https://bj.5i5j.com/ershoufang/']
custom_settings = {
'DEFAULT_REQUEST_HEADERS': {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36',
'Referer': 'https://bj.5i5j.com/'
},
'FEEDS': {
'items.json': {
'format': 'json',
'overwrite': True,
'indent': 4,
'fields': None,
'include_links': True,
}
}
}
# 添加MongoDB配置
mongo_uri = 'mongodb://localhost:27017/' # MongoDB URI
mongo_db = 'pachong' # MongoDB数据库名称
mongo_collection = 'pachong' # MongoDB集合名称
def __init__(self, *args, **kwargs):
super(Fivei5jSpider, self).__init__(*args, **kwargs)
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]
self.collection = self.db[self.mongo_collection]
def close(self, reason):
self.client.close()
super(Fivei5jSpider, self).close(self, reason)
def parse(self, response):
base_url = 'https://bj.5i5j.com' # 基础URL
# 定位具有特定类名的元素并提取链接
for element in response.css('.listTit'):
relative_link = element.css('a::attr(href)').get()
if relative_link:
# 构建完整的链接
full_link = base_url + relative_link
yield scrapy.Request(full_link, callback=self.parse_house)
# 获取下一页链接
next_page = response.css('a.cPage::attr(href)').get()
if next_page:
yield response.follow(next_page, callback=self.parse)
def parse_house(self, response):
house_name = response.xpath('/html/body/div[6]/div[1]/div[1]/h1/text()').get()
price = response.xpath('/html/body/div[6]/div[2]/div[2]/div[1]/div[1]/div[1]/span/text()').get()
agent_name = response.xpath('/html/body/div[6]/div[2]/div[2]/div[3]/ul/li[2]/h3/a/text()').get()
house_link = response.url # 获取当前页面的链接
# 提取基础属性信息和交易属性信息...
# 提取基础属性信息
basic_attributes = {
'房屋户型': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="房屋户型"]/span/text()').get(),
'所在楼层': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="所在楼层"]/span/text()').get(),
'建筑面积': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="建筑面积"]/span/text()').get(),
'户型结构': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="户型结构"]/span/text()').get(),
'套内面积': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="套内面积"]/span/text()').get(),
'建筑类型': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="建筑类型"]/span/text()').get(),
'房屋朝向': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="房屋朝向"]/span/text()').get(),
'建筑结构': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="建筑结构"]/span/text()').get(),
'装修情况': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="装修情况"]/span/text()').get(),
'供暖方式': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="供暖方式"]/span/text()').get(),
'配备电梯': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="配备电梯"]/span/text()').get()
}
# 提取交易属性信息
transaction_attributes = {
'发布时间': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="发布时间"]/span/text()').get(),
'建成年代': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="建成年代"]/span[1]/text()').get(),
'产权性质': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="产权性质"]/span/text()').get(),
'规划用途': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="规划用途"]/span/text()').get(),
'上次交易': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="上次交易"]/span/text()').get(),
'购房年限': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="购房年限"]/span/text()').get(),
'共有情况': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="共有情况"]/span/text()').get(),
'抵押情况': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="抵押情况"]/span/text()').get(),
'房本备件': response.xpath(
'/html/body/div[6]/div[3]/div[3]//ul/li[label/text()="房本备件"]/span/text()').get()
}
yield {
'房屋名称': house_name.strip() if house_name else None,
'价格': price.strip() if price else None,
'经纪人姓名': agent_name.strip() if agent_name else None,
'房屋链接': house_link, # 将房屋链接包含在输出中
'基础属性信息': basic_attributes,
'交易属性信息': transaction_attributes
}
# 将数据存储到MongoDB
data_to_insert = {
'房屋名称': house_name.strip() if house_name else None,
'价格': price.strip() if price else None,
'经纪人姓名': agent_name.strip() if agent_name else None,
'房屋链接': house_link, # 保留房屋链接在输出中
'基础属性信息': basic_attributes,
'交易属性信息': transaction_attributes
# 根据需要添加其他字段
}
# 插入数据到MongoDB集合中
self.collection.insert_one(data_to_insert)
yield data_to_insert
# 运行Spider
# scrapy crawl woaiwojia -o output.json # 您也可以将爬取的数据输出到文件中
要运行这个 Spider 并获取房产数据,您可以在命令行中执行以下命令:
scrapy crawl woaiwojia -o output.json
请将 woaiwojia
替换为您所创建的 Spider 的名称,output.json
是存储数据的输出文件名。
请确保mongodb数据库中已创建好数据表
运行成功后会生成一个json文件,里面包含了爬取到的信息
同时会将数据存入mongodb数据库,可以打开mongodb数据库查看,如果安装的是图形化界面,那么不再需要输入额外的命令,直接打开在表下就可以查看到,如果不是图形化界面,则需要使用命令进行查看,mongodb的安装本文不再做说明。
在mongodb安装文件目录下运行mongo
使用show dbs 命令查看已创建的数据库
show dbs
使用use exam命令切换到目标数据库,这里以“exam”数据库为例
use exam
使用db.exam.find()命令展示数据库中的内容
db.exam.find()
如果你的数据库名称不叫exam,请更改成你的数据库名称。
如果是图形化界面,直接打开就可以看到内容,不再演示。
本教程仅供教育和学习目的使用。作者力求提供准确和实用的信息,但不对信息的准确性、完整性和实时性作任何保证。读者在使用本教程中的任何信息、工具或代码时,须自行承担风险,并对其行为负全部责任。
作者对因使用本教程的信息、工具或代码所导致的任何直接或间接损失不承担责任。本教程中提供的代码示例仅供参考,读者应审慎检查代码并根据自身需求进行修改。
本教程中的所有内容,包括但不限于文本、图像、代码示例,版权均归作者所有。未经作者许可,禁止未经授权转载、复制或修改本教程中的任何内容。
读者可将本教程用于个人学习和研究目的,但不得用于商业目的或未经授权的传播。任何未经许可的使用可能构成侵权行为,作者保留采取法律行动的权利。
在任何情况下,本教程的信息均不构成任何形式的建议、担保或合同。作者保留随时更改或更新本教程内容的权利,无需提前通知。