资讯专栏INFORMATION COLUMN

从爬虫到机器学习预测,我是如何一步一步做到的?

Tamic / 1727人阅读

摘要:数据分析实战北京二手房房价分析数据分析实战北京二手房房价分析建模篇除了数据分析,好多朋友也对爬虫特别感兴趣,想知道爬虫部分是如何实现的。爬取目标是北京二手房,仅针对一个城市而言,数据量并不大。

作者:xiaoyu

微信公众号:Python数据科学

知乎: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

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

具体详细框架结构可参见:Python爬虫之Scrapy学习(基础篇)

爬虫解析部分,是在继承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数据。

BeautifulSoup的具体使用方法参见:Python爬虫之BeautifulSoup解析之路

爬取获得的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客
这部分之前就有分享过,可以参见:Scrapy爬取二手房信息+可视化数据分析

以下是核心的爬虫部分,与链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数据科学,发现更多精彩内容。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/18461.html

相关文章

  • 搜索引擎(0xFE)--- 用机器学习再谈排序

    摘要:今天,说说如何用机器学习的办法来进行排序商品本身的属性排序。开始排序好了,前期准备工作完成了,目标也确定了,我们开始机器学习的排序了。 这里没有标记颜色,可能看起来重点不突出,可以去微信页面观看这里 前面说排序的时候已经简单了说了一下排序的方法,包括三部分:相关性排序,商品本身的属性排序,个性化排序,无论怎么排,大体上都逃不掉这三项。 最近看到一篇文章有赞搜索引擎实践(算法篇),中间有...

    laoLiueizo 评论0 收藏0
  • Python爬虫学习路线

    摘要:以下这些项目,你拿来学习学习练练手。当你每个步骤都能做到很优秀的时候,你应该考虑如何组合这四个步骤,使你的爬虫达到效率最高,也就是所谓的爬虫策略问题,爬虫策略学习不是一朝一夕的事情,建议多看看一些比较优秀的爬虫的设计方案,比如说。 (一)如何学习Python 学习Python大致可以分为以下几个阶段: 1.刚上手的时候肯定是先过一遍Python最基本的知识,比如说:变量、数据结构、语法...

    liaoyg8023 评论0 收藏0
  • 0开始如何用一个月杀进机器学习比赛Top25%

    摘要:可以去上培训班,交点钱,但也就跟机器学习混个脸熟。机器学习理论基础知识固然重要,但是在我看来兴趣和好玩更为重要。一个月的时间自己仅仅是学习了机器学习中的一点皮毛,在未来机器学习的旅途中已经给自己做了一个规划。 比赛介绍 为贯彻习近平主席在十九大报告中关于推动互联网、大数据、人工智能和实体经济深度融合以及善于运用互联网技术和信息化手段开展工作等讲话精神,引导高校在校生学习掌握计算机与互联...

    keke 评论0 收藏0
  • 利用Python爬取百度贴吧图片

    摘要:背景介绍我大一的时候学校就开设了,但是并没有好好学,基本等于是什么也不会,最近才开始看,所以本身也是摸着石头过河,见谅心得讲真的,爬虫确实不像别人想象的那样简单,爬虫首先要静下心来,细心寻找目标网站的布局规律,最重要的是的变化,这是一个考验 背景介绍 我大一的时候学校就开设了 python,但是并没有好好学,基本等于是什么也不会,最近才开始看,所以本身也是摸着石头过河,见谅... 心得...

    YPHP 评论0 收藏0
  • Python

    摘要:最近看前端都展开了几场而我大知乎最热语言还没有相关。有关书籍的介绍,大部分截取自是官方介绍。但从开始,标准库为我们提供了模块,它提供了和两个类,实现了对和的进一步抽象,对编写线程池进程池提供了直接的支持。 《流畅的python》阅读笔记 《流畅的python》是一本适合python进阶的书, 里面介绍的基本都是高级的python用法. 对于初学python的人来说, 基础大概也就够用了...

    dailybird 评论0 收藏0

发表评论

0条评论

Tamic

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<