用scrapy爬取58同城安居客租房信息
最近有租房需求,需要整合一下各个网站的租房信息,于是想写一个脚本,定时爬取入库。
编码准备
- scrapy
- rds数据库
- ip代理池
创建项目
可以使用scrapy的自带命令创建项目
# 创建项目
scrapy startproject house_need
# 进入项目目录
cd house_need
# 创建爬虫
scrapy genspider house_spider
设置文件
在编写爬虫之前,我们需要对这个项目的一些特性进行设置,下面是一些修改示例:
# ./settings.py文件修改
# 数据库信息,这里使用mysql
DATABASE_INFO = {
"host": "",
"port": 3306,
"user": "user",
"pwd": "pwd",
"db": "house",
"char": "utf8mb4",
}
# 是否使用代理
USE_PROXIES = True
# 代理ip 这里最好使用自动获取或者文件获取
PROXIES = [
{
"ip_port": "host:port",
"user_passwd": None,
},
]
# 一些user_agent
USER_AGENT = [
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
]
# 是否遵从robots.txt规则 不允许
ROBOTSTXT_OBEY = False
编写中间件和管道
上一步中我们启用了代理,并配置了数据库。在爬虫访问页面之前会调用中间件里的方法,使用代理;在爬虫爬取有效数据之后会走管道,对数据进行进一步处理,比如:清洗、入库;
编写中间件:
# ...
from house_need.settings import PROXIES, USE_PROXIES, USER_AGENT
# ...
class HouseNeedDownloaderMiddleware:
# ...
def process_request(self, request, spider):
# 随机USER_AGENT
ua = random.choice(USER_AGENT)
print("USER_AGENT: " + ua)
request.headers['User-Agent'] = ua
if USE_PROXIES :
proxy = random.choice(PROXIES)
# 没有代理用户密码
request.meta["proxy"] = "http://" + proxy["ip_port"]
print("USE_PROXY: " + proxy["ip_port"])
else :
return None
# ...
编写管道,这里我们只做简单的入库处理:
第一步,在items.py中编写我们所需要抓取的数据维度
class HouseNeedItem(scrapy.Item):
# 来源
source = scrapy.Field()
# 标题
title = scrapy.Field()
# 户型
room = scrapy.Field()
# 面积
size = scrapy.Field()
# 与地铁站距离
far = scrapy.Field()
# 小区名称
name = scrapy.Field()
# 地区
area = scrapy.Field()
# 头图
pic = scrapy.Field()
# 价格/月
money = scrapy.Field()
第二步,在pipelines.py中做入库操作,使用pymysql
from itemadapter import ItemAdapter
from house_need.settings import DATABASE_INFO
import pymysql
class HouseNeedPipeline:
def __init__(self):
self.db = pymysql.connect(DATABASE_INFO['host'], DATABASE_INFO['user'], DATABASE_INFO['pwd'], DATABASE_INFO['db'], charset=DATABASE_INFO['char'], port=DATABASE_INFO['port'])
self.cursor = self.db.cursor()
def process_item(self, item, spider):
sql = "REPLACE INTO house_spider (subway, title, name, area, far, money, source) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', %d)" % ('杨家湾', item['title'], item['name'], item['area'], item['far'], item['money'], item['source'])
print(sql)
self.cursor.execute(sql)
# 使用REPLACE_INTO判断返回行数,如果为1则为新数据(索引 title&source)
if self.cursor.rowcount == 1 :
print('新数据 发送邮件通知')
self.db.commit()
print('REPLACR INTO SUCCESSFULL')
return item
def close_spider(self, spider):
self.cursor.close()
self.db.close()
数据表设计如下:
CREATE TABLE `house_spider` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`subway` varchar(10) NOT NULL DEFAULT '' COMMENT '地铁站',
`title` varchar(100) NOT NULL DEFAULT '' COMMENT '标题',
`name` varchar(100) NOT NULL DEFAULT '' COMMENT '小区名称',
`area` varchar(20) NOT NULL DEFAULT '' COMMENT '地区',
`far` varchar(50) NOT NULL DEFAULT '' COMMENT '距离描述',
`money` varchar(10) NOT NULL DEFAULT '' COMMENT '金额',
`source` tinyint(1) NOT NULL DEFAULT '1' COMMENT '158 2安居客',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `IDX_TITLE_SOURCE` (`title`,`source`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=293 DEFAULT CHARSET=utf8mb4
第三步,在设置文件中启用中间件和管道
DOWNLOADER_MIDDLEWARES = {
'house_need.middlewares.HouseNeedDownloaderMiddleware': 543,
}
ITEM_PIPELINES = {
'house_need.pipelines.HouseNeedPipeline': 300,
}
至此,一些必要的设置已经完成,下一步就开始专注于爬虫编写
编写爬虫
整体浏览一下页面,发现我们需要的数据主要集中在所有的@class="house-cell realverify"下面
于是,根据页面结构写出相应的xpath语法:
import scrapy
from house_need.items import HouseNeedItem
class HouseSpider(scrapy.Spider):
name = "house_spider"
start_urls = [
# 页面地址
'https://wh.58.com/zufang/sub/l89/s3741/j2/',
]
def parse(self, response):
item = HouseNeedItem()
house_div = response.xpath("//li[@class='house-cell realverify']")
for each in house_div :
item['source']= 1
item['title'] = each.xpath(".//div[@class='des']//h2//a/text()").extract()[0].strip()
item['far'] = each.xpath(".//div[@class='des']//p[@class='infor']/text()").extract()[3].strip()
item['name'] = each.xpath(".//div[@class='des']//p[@class='infor']//a/text()").extract()[1].strip()
item['area'] = each.xpath(".//div[@class='des']//p[@class='infor']//a/text()").extract()[0].strip()
item['money'] = each.xpath(".//div[@class='list-li-right']//div[@class='money']//b/text()").extract()[0].strip()
print(item)
yield item
运行爬虫
在./house_need目录下运行:
scrapy crawl house_spider
可以看到入库正常。
安居客的页面大同小异,只需要新增spider文件即可。
评论已关闭