作者:xiaoyu

微信公众号:Python数据科学

前情回顾

前一段时间与大家分享了北京二手房房价分析的实战项目,分为分析和建模两篇。文章发出后,得到了大家的肯定和支持,在此表示感谢。

除了数据分析,好多朋友也对爬虫特别感兴趣,想知道爬虫部分是如何实现的。本篇将分享这个项目的爬虫部分,算是数据分析的一个 前传篇。

爬虫前的思考

爬虫部分主要是通过爬取链x和安x客来获取二手房住房信息,因为考虑到不同网站的房源信息可以互补,所以选择了两个网站。

爬取目标是北京二手房,仅针对一个城市而言,数据量并不大。所以直接采用Scrapy来完成爬取工作,然后将数据存储在csv格式的文件中。最终爬取结果是这样的,链x的爬虫爬取了 30000+条数据,安x客的爬虫爬取了 3000+条数据。不得不说链x的房源相对来讲还是比较全的。

scrapy爬取链x

写一个爬虫最开始当然要想清楚需要获取什么样的数据了。本次项目对与二手房相关的数据都比较感兴趣,可以自然的想到,每个房源链接的具体详细信息是最全的。但考虑到爬虫深度影响整体爬虫效率问题,并且房源列表中数据已经能够满足基本的要求,并没有必要对每个详细链接进行深入的爬取,因此最终选择爬取房源列表。以下是房源列表(部分截图)中的房源信息:

确定以上爬取内容后,就开始爬虫部分的工作。首先在item.py文件中定义一个子类,该子类继承了父类scrapy.Item,然后在子类中用scrapy.Field()定义以上信息的字段。如下代码,将所有需要的字段信息都设置好。

import scrapy

class LianjiaSpiderItem(scrapy.Item):

# define the fields for your item here like:

Id = scrapy.Field()

Region = scrapy.Field()

Garden = scrapy.Field()

Layout = scrapy.Field()

Size = scrapy.Field()

Direction = scrapy.Field()

Renovation = scrapy.Field()

Elevator = scrapy.Field()

Floor = scrapy.Field()

Year = scrapy.Field()

Price = scrapy.Field()

District = scrapy.Field()

pass

在spider文件夹下的爬取文件(自定义)中导入所需库,如下代码:

json:json格式的转换;

scrapy:scrapy库;

logging:日志;

BeautifulSoup:使用bs4提取网页信息;

table:settings中自设的一个字典;

LianjiaSpiderItem:字段Field;

# -*- coding:utf-8 -*-

import json

import scrapy

import logging

from bs4 import BeautifulSoup

from lianjia_spider.settings import table

from lianjia_spider.items import LianjiaSpiderItem

下面进入关键部分,即爬虫部分。这部分主要需要自己做的就是如何解析,而对于爬虫是如何爬取的我们不用关心,因为它是框架已经在底层完成调度和爬取的实现,我们只要简单调用即可。

爬虫解析部分,是在继承scrapy.Spider父类的子类LianjiaSpider中完成的。子类中设有三个函数,并通过callback回调逐层实现解析功能,这三个函数是:

start_requests:覆盖父类中原有函数,爬取初始url并存入消息队列中;

page_navigate:解析初始url页面,循环爬取各初始url页面下的所有页码链接;

parse:爬取每个页码下的所有详细房源链接,提取相应的字段信息,并储存至items中;

下面是三个函数的功能描述,以及代码实现。

start_requests

任何爬虫都需要有初始url,然后由初始url继续深入爬取进一步的url,直到爬取到所需数据。由于链家二手房url的特征是,由一个基础url和各大区拼音拼接组成,因此在start_requests函数中定义了base_url的基础url,和需要拼接的北京各大区的拼音列表。

然后由这些拼接的各大区url作为所有的初始url链接,并由scrapy.Request方法对每个链接发出异步请求,代码如下:

class LianjiaSpider(scrapy.Spider):

name = 'lianjia'

base_url = 'https://bj.lianjia.com/ershoufang/'

def start_requests(self):

district = ['dongcheng', 'xicheng', 'chaoyang', 'haidian', 'fengtai', 'shijingshan', 'tongzhou', 'changping',

'daxing', 'yizhuangkaifaqu', 'shunyi', 'fangshan', 'mentougou', 'pinggu', 'huairou',

'miyun', 'yanqing', 'yanjiao', 'xianghe']

for elem in district:

region_url = self.base_url + elem

yield scrapy.Request(url=region_url, callback=self.page_navigate)

page_navigate

对每个大区url发出异步请求后,我们需要对各大区内的所有房源列表url进行进一步的爬取,而为了能够顺利的将全部内容爬取,我们就要解决页码循环的问题。在page_navigate函数中,使用BeautifulSoup解析html,提取页面中的pages数据。

爬取获得的pages数据是json字符串,所以需要使用json.loads将其转换为字典格式,然后得到max_number。最后通过for循环不断发送每个页码url的链接完成异步请求,并使用callback调用进入下一步的函数中,代码如下:

def page_navigate(self, response):

soup = BeautifulSoup(response.body, "html.parser")

try:

pages = soup.find_all("div", class_="house-lst-page-box")[0]

if pages:

dict_number = json.loads(pages["page-data"])

max_number = dict_number['totalPage']

for num in range(1, max_number + 1):

url = response.url + 'pg' + str(num) + '/'

yield scrapy.Request(url=url, callback=self.parse)

except:

logging.info("*******该地区没有二手房信息********")

parse

parse函数中,首先通过BeautifulSoup解析每个页码下的所有房源列表信息,得到house_info_list。链x房源列表中没有所在大区信息,但是房源所在区域对于后续数据分析是很重要的,而仅通过页面解析我们没办法获取。为了获得这个字段该如何实现呢?

我们可以通过response.url来判断,因为url正好是我们开始用所在区域拼接而成的,我们构造url的时候已经包含了大区信息。那么简单的通过辨识url中的大区拼音,就可以解决该问题了。然后使用字典table将对应的中文所在区名映射到Region字段中。

接下来开始对房源列表 house_info_list中的每个房源信息info进行解析。根据链x的页面结构,可以看到,每个info下有三个不同位置的信息组,可通过class_参数进行定位。这三个位置信息分别是house_info,position_info,price_info,每组位置下包含相关字段信息。

house_info:如图包含Garden,Size,Layout,Direction,Renovation,Elevator房屋构造等字段信息;

position_info:如图包含Floor,Year,District等位置年限字段信息;

price_info:如图包含Total_price,price等字段信息;

这里说的位置不同是在前端html页面中的标签位置不同。

具体操作方法参见下面代码:

def parse(self, response):

item = LianjiaSpiderItem()

soup = BeautifulSoup(response.body, "html.parser")

#获取到所有子列表的信息

house_info_list = soup.find_all(name="li", class_="clear")

# 通过url辨认所在区域

url = response.url

url = url.split('/')

item['Region'] = table[url[-3]]

for info in house_info_list:

item['Id'] = info.a['data-housecode']

house_info = info.find_all(name="div", class_="houseInfo")[0]

house_info = house_info.get_text()

house_info = house_info.replace(' ', '')

house_info = house_info.split('/')

# print(house_info)

try:

item['Garden'] = house_info[0]

item['Layout'] = house_info[1]

item['Size'] = house_info[2]

item['Direction'] = house_info[3]

item['Renovation'] = house_info[4]

if len(house_info) > 5:

item['Elevator'] = house_info[5]

else:

item['Elevator'] = ''

except:

print("数据保存错误")

position_info = info.find_all(name='div', class_='positionInfo')[0]

position_info = position_info.get_text()

position_info = position_info.replace(' ', '')

position_info = position_info.split('/')

# print(position_info)

try:

item['Floor'] = position_info[0]

item['Year'] = position_info[1]

item['District'] = position_info[2]

except:

print("数据保存错误")

price_info = info.find_all("div", class_="totalPrice")[0]

item['Price'] = price_info.span.get_text()

yield item

对于链x的爬取,没用xpath的原因是提取一些标签实在不是很方便(只是针对于链x),因此博主采用了beautifulSoup。

scrapy爬取安x客

以下是核心的爬虫部分,与链x爬取部分的思想一致,不同的是使用了xpath进行解析和ItemLoader对item加载储存。

# -*- coding:utf-8 -*-

import scrapy

from scrapy.loader import ItemLoader

from anjuke.items import AnjukeItem

class AnjukeSpider(scrapy.Spider):

name = 'anjuke'

custom_settings = {

'REDIRECT_ENABLED': False

}

start_urls = ['https://beijing.anjuke.com/sale/']

def start_requests(self):

base_url = 'https://beijing.anjuke.com/sale/'

for page in range(1, 51):

url = base_url + 'p' + str(page) + '/'

yield scrapy.Request(url=url, callback=self.parse)

def parse(self, response):

num = len(response.xpath('//*[@id="houselist-mod-new"]/li').extract())

house_info = response.xpath('//*[@id="houselist-mod-new"]')

print(house_info)

for i in range(1, num + 1):

l = ItemLoader(AnjukeItem(), house_info)

l.add_xpath('Layout', '//li[{}]/div[2]/div[2]/span[1]/text()'.format(i))

l.add_xpath('Size', '//li[{}]/div[2]/div[2]/span[2]/text()'.format(i))

l.add_xpath('Floor', '//li[{}]/div[2]/div[2]/span[3]/text()'.format(i))

l.add_xpath('Year', '//li[{}]/div[2]/div[2]/span[4]/text()'.format(i))

l.add_xpath('Garden', '//li[{}]/div[2]/div[3]/span/text()'.format(i))

l.add_xpath('Region', '//li[{}]/div[2]/div[3]/span/text()'.format(i))

l.add_xpath('Price', '//li[{}]/div[3]/span[1]/strong/text()'.format(i))

yield l.load_item()

安x客的反爬比较严重,如果不使用代理ip池,速度过快非常容易挂掉。而链x的反爬相对没那么严格,速度可以很快。

总结

以上是对本项目爬虫部分核心内容的分享,至此这个项目完成了从爬虫到数据分析,再到数据挖掘预测的 "三部曲"完整过程。虽然这个项目比较简单,仍有很多地方需要完善,但是希望通过这个项目能让大家对整个过程有个很好的认识和了解。

关注微信公众号:Python数据科学,发现更多精彩内容。

python爬虫预测_从爬虫到机器学习预测,我是如何一步一步做到的?相关推荐

  1. bagging和时间序列预测_时间序列的LSTM模型预测——基于Keras

    一.问题背景     现实生活中,在一系列时间点上观测数据是司空见惯的活动,在农业.商业.气象军事和医疗等研究领域都包含大量的时间序列数据.时间序列的预测指的是基于序列的历史数据,以及可能对结果产生影 ...

  2. CNN做时间序列预测_深度学习与时间序列预测

    论文下载地址: N-BEATS: Neural basis expansion analysis for interpretable time series forecasting​arxiv.org ...

  3. python多线程爬虫框架_普通爬虫vs多线程爬虫vs框架爬虫,Python爬对比

    前言 本文的文字及图片过滤网络,可以学习,交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. 基本开发环境 Python 3.6 皮查姆 目标网页分析 网站就选择发表情这个网站吧 网站是静 ...

  4. python龙虎榜数据_【爬虫】使用爬虫技术获取盘后龙虎榜

    原文来自:MindGo量化社区-[爬虫]使用爬虫技术获取盘后龙虎榜 [导语]本文是"爬虫"系列文章的第一篇.爬虫技术被广泛用于搜索引擎.数据采集等重要领域.搜索引擎提供海量搜索结果 ...

  5. python爬图片_网络爬虫经验:反爬和反反爬

    我想很多人入门python是图片爬虫,就是HTTP请求,保存一下图片,用python实现非常快.网上很多爬虫的教程就讲到这里,实际上很单一,看了跟没看没什么区别,都是找一下网页的规律,然后Beauti ...

  6. python花瓣图_【爬虫】花瓣图片爬虫,Python图片采集下载源码

    #https://huaban.com/search/?q=纹理&category=industrial_design #by 微信:huguo00289 # -*- coding: UTF- ...

  7. lime 深度学习_用LIME解释机器学习预测并建立信任

    lime 深度学习 It's needless to say: machine learning is powerful. 不用说:机器学习功能强大. At the most basic level, ...

  8. python基于svm实现指数预测_基于SVM的股票预测 Python实现 附Github

    SVM 支持向量机 原理就不赘述了,其余的文章有讲过.SVM是一种十分优秀的分类算法,使用SVM也能给股票进行一定程度上的预测. 核心 因为是分类算法,因此不像ARIMA一样预测的是时序.分类就要有东 ...

  9. java 时间序列预测_基于spark的时间序列预测包Sparkts._的使用

    最近研究了一下时间序列预测的使用,网上找了大部分的资源,都是使用python来实现的,使用python来实现虽然能满足大部分的需求,但是python有一点缺点按就是只能使用一台计算资源进行计算,如果数 ...

最新文章

  1. android7.1.1大小,浅谈Android7.1.1 for 360 N5
  2. 第一个问题就难倒我了!
  3. 状态模式 设计模式_设计模式:状态
  4. 怎样查看Jdk是32位还是64位
  5. qt利用QSplitter任意拆分窗口
  6. [Unity脚本运行时更新]C#7.2新特性
  7. win7的一些小知识
  8. html标签整合和css框架处理
  9. python基础学习1-字典的使用
  10. 重庆自考学历计算机应用基础考试,2017年自考计算机应用基础模拟试题1
  11. 时间linux防火墙策略,Linux防火墙简介 – iptables配置策略(示例代码)
  12. 顶隙计算公式_齿轮参数计算公式,这次终于整全了
  13. pipreqs 命令 ConnectionResetError(10054, ‘An existing connection was forcibly closed by the remote hos
  14. cad多段线画圆弧方向_【学员分享】CAD多段线用法
  15. 关于计算机的论文英语2000字,英语论文2000字左右
  16. vue 动态渲染背景图片
  17. [全新大碟]周杰倫 - 魔杰座
  18. 【心理咨询师考试笔记】操作技能(二)——心理评估
  19. NSFC 申请不中的反思 (内部讨论)
  20. springBoot 拦截器与过滤器

热门文章

  1. .net 初学者。学习笔记 [获取varchar32主键的最大ID值]
  2. msm8953 fm设置频段流程
  3. xcode与androidstudio 设置自定义主题
  4. windows之2012缺少api-ms-win-crt**.dll
  5. 图像处理自学(五):CAMERA驱动软件硬件架构V4L2
  6. 视频编解码(六):264解码器学习
  7. 威联通NAS-QTS系统中一些功能的释义
  8. 解决Element的 InfiniteScroll 无限滚动组件报错
  9. python json dumps 中文_Python下调用json.dumps中文显示问题解决办法
  10. linux软连接目标不存在,Linux ln创建软连接之后无法使用,无法whereis