scrapy自动抓取蛋壳公寓最新房源信息并存入sql数据库
利用scrapy抓取蛋壳公寓上的房源信息,以北京市为例,目标url:https://www.dankegongyu.com/room/bj
思路分析
每次更新最新消息,都是在第一页上显示,因此考虑隔一段时间自动抓取第一页上的房源信息,实现抓取最新消息。
利用redis的set数据结构的特征,将每次抓取后的url存到redis中;
每次请求,将请求url与redis中的url对比,若redis中已存在该url,代表没有更新,忽略该次请求;若redis中不存在该url,代表该信息是新信息,抓取并将url存入到redis中。
分析页面源码,发现该网页属于静态网页;首先获取最新页面每条数据的url,请求该url,得到详细页面情况,所有数据均从详情页面获取。
代码实现
明确抓取字段
# -*- coding: utf-8 -*- # Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html import scrapy class DankeItem(scrapy.Item):
"""
编辑带爬取信息字段
"""
# 数据来源
source = scrapy.Field()
# 抓取时间
utc_time = scrapy.Field() # 房间名称
room_name = scrapy.Field()
# 房间租金
room_money = scrapy.Field()
# 房间面积
room_area = scrapy.Field()
# 房间编号
room_numb = scrapy.Field()
# 房间户型
room_type = scrapy.Field()
# 租房方式
rent_type = scrapy.Field()
# 房间楼层
room_floor = scrapy.Field()
# 所在区域
room_loca = scrapy.Field()
# 所在楼盘
estate_name = scrapy.Field()
编写爬虫逻辑
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from danke.items import DankeItem class DankeSpider(CrawlSpider): # 爬虫名
name = 'dkgy3' # 允许抓取的url
allowed_domains = ['dankegongyu.com'] custom_settings = {'DOWNLOAD_DELAY': 0.2} # 请求开始的url
start_urls = ['https://www.dankegongyu.com/room/sz'] # rules属性
rules = ( #编写匹配详情页的规则,抓取到详情页的链接后不用跟进
Rule(LinkExtractor(allow=r'https://www.dankegongyu.com/room/\d+'), callback='parse_detail', follow=False),
) def parse_detail(self, response):
"""
解析详情页数据
:param response:
:return:
"""
node_list = response.xpath('//div[@class="room-detail-right"]')
for node in node_list:
item = DankeItem() # 房间名称
room_name = node.xpath('./div/h1/text()')
item['room_name'] = room_name.extract_first() # 房间租金
room_money = node.xpath('./div[@class="room-price"]/div/span').xpath('string(.)').extract_first() # 有的房子有首月租金,和普通租金不同,因此匹配方式也不同
if room_money:
item['room_money'] = room_money
else:
room_money = node.xpath('./div[@class="room-price hot"]/div/div[@class="room-price-num"]/text()').extract_first()
item['room_money'] = room_money
print(room_money) # 房间面积
room_area = node.xpath('./*/div[@class="room-detail-box"]/div[1]/label/text()').extract_first().split(':')[-1]
item['room_area'] = room_area # 房间编号
room_numb = node.xpath('./*/div[@class="room-detail-box"]/div[2]/label/text()').extract_first().split(':')[-1]
item['room_numb'] = room_numb # 房间户型
room_type = node.xpath('./*/div[@class="room-detail-box"]/div[3]/label/text()').extract_first().split(':')[-1]
item['room_type'] = room_type # 租房方式
rent_type = node.xpath('./*/div[@class="room-detail-box"]/div[3]/label/b/text()').extract_first().split(':')[
-1]
item['rent_type'] = rent_type # 所在楼层
room_floor = node.xpath('./div[@class="room-list-box"]/div[2]/div[2]').xpath('string(.)').extract_first().split(':')[-1]
item['room_floor'] = room_floor # 所在区域
room_loca = node.xpath('./div[@class="room-list-box"]/div[2]/div[3]/label/div/a[1]/text()').extract_first()
item['room_loca'] = room_loca # 所在楼盘
estate_name = node.xpath('./div[@class="room-list-box"]/div[2]/div[3]/label/div/a[3]/text()').extract_first()
item['estate_name'] = estate_name yield item
编写下载中间件
下载中间件中实现两个逻辑:添加随机请求头和url存入redis中
# -*- coding: utf-8 -*- # Define here the models for your spider middleware
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/spider-middleware.html
import time
import random
import hashlib
import redis
from scrapy.exceptions import IgnoreRequest
from danke.settings import USER_AGENTS as ua class DankeSpiderMiddleware(object):
def process_request(self, request, spider):
"""
给每一个请求随机分配一个代理
:param request:
:param spider:
:return:
"""
user_agent = random.choice(ua)
request.headers['User-Agent'] = user_agent class DankeRedisMiddleware(object):
"""
将第一个页面上的每一个url放入redis的set类型中,防止重复爬取
"""
# 连接redis
def __init__(self):
self.redis = redis.StrictRedis(host='39.106.116.21', port=6379, db=3) def process_request(self, request, spider): # 将来自详情页的链接存到redis中
if request.url.endswith(".html"):
# MD5加密详情页链接
url_md5 = hashlib.md5(request.url.encode()).hexdigest() # 添加到redis,添加成功返回True,否则返回False
result = self.redis.sadd('dk_url', url_md5) # 添加失败,说明链接已爬取,忽略该请求
if not result:
raise IgnoreRequest
数据存储
# -*- coding: utf-8 -*- from datetime import datetime
import pymysql class DankeSourcePipeline(object):
def process_item(self, item, spider):
item['source'] = spider.name
item['utc_time'] = str(datetime.utcnow())
return item class DankePipeline(object): def __init__(self): self.conn = pymysql.connect(
host='39.106.116.21',
port=3306,
database='***',
user='***',
password='****',
charset='utf8'
)
# 实例一个游标
self.cursor = self.conn.cursor() def process_item(self, item, spider): sql = ("insert into result_latest(标题, 租金, 面积, "
"编号, 户型, 出租方式, 楼层, "
"区域, 楼盘, 抓取时间, 数据来源)"
"values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)") item = dict(item) data = [
item['room_name'],
item['room_money'],
item['room_area'],
item['room_numb'],
item['room_type'],
item['rent_type'],
item['room_floor'],
item['room_loca'],
item['estate_name'],
item['utc_time'],
item['source'],
]
self.cursor.execute(sql, data)
# 提交数据
self.conn.commit() return item def close_spider(self, spider):
self.cursor.close()
self.conn.close()
实现自动爬取
import os
import time while True:
"""
每隔20*60*60 自动爬取一次,实现自动更新
"""
os.system("scrapy crawl dkgy3")
time.sleep(20*60*60) # from scrapy import cmdline
# cmdline.execute("scrapy crawl dkgy3".split())
完整代码
参见:https://github.com/zInPython/danke
scrapy自动抓取蛋壳公寓最新房源信息并存入sql数据库的更多相关文章
- scrapy实现自动抓取51job并分别保存到redis,mongo和mysql数据库中
项目简介 利用scrapy抓取51job上的python招聘信息,关键词为“python”,范围:全国 利用redis的set数据类型保存抓取过的url,现实避免重复抓取: 利用脚本实现每隔一段时间, ...
- 学习笔记CB010:递归神经网络、LSTM、自动抓取字幕
递归神经网络可存储记忆神经网络,LSTM是其中一种,在NLP领域应用效果不错. 递归神经网络(RNN),时间递归神经网络(recurrent neural network),结构递归神经网络(recu ...
- 【VIP视频网站项目】VIP视频网站项目v1.0.3版本发布啦(程序一键安装+电影后台自动抓取+代码结构调整)
在线体验地址:http://vip.52tech.tech/ GIthub源码:https://github.com/xiugangzhang/vip.github.io 项目预览 主页面 登录页面 ...
- SQL Server定时自动抓取耗时SQL并归档数据发邮件脚本分享
SQL Server定时自动抓取耗时SQL并归档数据发邮件脚本分享 第一步建库和建表 USE [master] GO CREATE DATABASE [MonitorElapsedHighSQL] G ...
- IIS崩溃时自动抓取Dump
背景:在客户现场,IIS有时会崩溃,开发环境没法重现这个bug,唯有抓取IIS的崩溃是的Dump文件分析. IIS崩溃时自动抓取Dump,需要满足下面几个条件 1.启动 Windows Error R ...
- 自动抓取java堆栈
参数1 进程名字,参数2 最大线程数 例: pid为8888,达到1000个线程时自动抓取堆栈信息 ./autojstack.sh 8888 1000 & #!/bin/bashfileNam ...
- SQL Server定时自动抓取耗时SQL并归档数据脚本分享
原文:SQL Server定时自动抓取耗时SQL并归档数据脚本分享 SQL Server定时自动抓取耗时SQL并归档数据脚本分享 第一步建库 USE [master] GO CREATE DATABA ...
- APP自动化框架LazyAndroid使用手册(2)--元素自动抓取
作者:黄书力 概述 前面的一篇博文简要介绍了安卓自动化测试框架LazyAndroid的组成结构和基本功能,本文将详细描述此框架中元素自动抓取工具lazy-uiautomaterviewer的使用方法. ...
- 巧用Grafana和Arthas自动抓取K8S中异常Java进程的线程堆栈
前言 近期发现业务高峰期时刻会出现CPU繁忙导致的timeout异常,通过监控来看是因为Node上面的一些Pod突发抢占了大量CPU导致的. 问: 没有限制CPU吗?是不是限制的CPU使用值就可以解决 ...
随机推荐
- Vuforia添加虚拟按键
AR虚拟按键为真实识别图上的按键,通过按键可以实现真实与虚拟之间的按键交流 (一)添加按键 点击target,打开advance,添加虚拟按键,即可在此target下添加虚拟按键 注:虚拟按键无法旋转 ...
- IntelliJ IDEA 配置Maven仓库
1. 下载Maven 官方地址:http://maven.apache.org/download.cgi 2. 修改本地仓库路径 3. 设置环境变量 MAVEN_HOME: E:\DevelopEnv ...
- (Git) 优秀Java,Vue项目推荐
Java 1.spring-boot-pay 地址:小柒2012/spring-boot-pay 这是一个支付案例,提供了包括支付宝.微信.银联在内的详细支付代码案例,对于有支付需求的小伙伴来说,这个 ...
- 一个开源组件 bug 引发的分析
这是一个悲伤的故事.某日清晨,距离版本转测还剩一天,切图仔的我正按照计划有条不紊的画页面.当我点击一个下拉弹框组件中分页组件页数过多而出现的向后 5 页省略号时,悲剧开始了,弹框被收回了.情景再现 问 ...
- 哪种方式更适合在React中获取数据?
作者:Dmitri Pavlutin 译者:小维FE 原文:dmitripavlutin.com 国外文章,笔者采用意译的方式,以保证文章的可读性. 当执行像数据获取这样的I/O操作时,你必须发起获取 ...
- MIT线性代数:20.克拉默法则,逆矩阵和体积
- [Hadoop]HDFS机架感知策略
HDFS NameNode对文件块复制相关所有事物负责,它周期性接受来自于DataNode的HeartBeat和BlockReport信息,HDFS文件块副本的放置对于系统整体的可靠性和性能有关键性影 ...
- N42期-qq-林友埙-第一周作业
1.按系列罗列Linux的发行版,并描述不同发行版之间的联系与区别. 基于Dpkg (Debian系) 商业发行版 o Ubuntu,一个非常流行的桌面发行版. 社区发行版 o Debian,一个强烈 ...
- vim编辑器介绍
所有的 Unix Like 系统都会内建 vi 文书编辑器,其他的文书编辑器则不一定会存在. 但是目前我们使用比较多的是 vim 编辑器. vim 具有程序编辑的能力,可以主动的以字体颜色辨别语法的正 ...
- python学习之【第五篇】:Python中的元组及其所具有的方法
1.前言 Python的元组(tuple)与列表很相似,不同之处在于元组不能被修改,即元组一旦创建,就不能向元组中的增加新元素,不能删除元素中的元素,更不能修改元组中元素.但是元组可以访问任意元素,可 ...