安居客scrapy房產信息爬取到數據可視化(上)-scrapy爬蟲


出發點

想做一個地圖熱力圖,發現安居客房產數據有我要的特性。emmm,那就嘗試一次好了~

老規矩,從爬蟲,從拿到數據開始...

 

 

scrapy的配置

創建一個項目(在命令行下敲~):

scrapy startproject anjuke

這命令會建一個叫anjuke的文件夾,里面會有一些待你配置的文件

 

創建一個spider:

先進入創建的項目文件夾里

cd anjuke
scrapy genspider anju qd.anjuke.com

這命令會建一個叫anju.py的文件,它就是剛剛創建的spider

 

這時的文件夾結構應該是這樣的:

 

創建item

item是保存爬取數據的容器,使用方法和字典類似~

將item.py修改如下:

import scrapy


class AnjukeItem(scrapy.Item):
    # define the fields for your item here like:
    address = scrapy.Field()
    name = scrapy.Field()
    type_ = scrapy.Field()
    tags = scrapy.Field()
    price = scrapy.Field()
    area = scrapy.Field()
    city = scrapy.Field()

至於item為什么是這樣的可以看看這張圖片:

網頁結構:

 

上圖就是下面代碼用xpath獲取divs的那部分,這跟網頁的結構有關~

 

 

瀏覽器直接按f12審查元素就是這個站的源碼了(有的網站有些內容由js加載時,其實這里可能不是返回的源碼)。

上圖列出了下面xpath代碼的邏輯~~

 

spider的邏輯(spider-anju.py的修改)

# -*- coding: utf-8 -*-
import scrapy
from anjuke.items import AnjukeItem  # 使用item


class AnjuSpider(scrapy.Spider):
    name = 'anju'  # spider的名稱,影響不大
    allowed_domains = []  # 允許爬取的域,為空則是允許當前spider爬取所有的域名
    start_urls = ['https://cheng.fang.anjuke.com/', 'https://chang.fang.anjuke.com/', 'https://chi.fang.anjuke.com/',
                  'https://chu.fang.anjuke.com/', 'https://cy.fang.anjuke.com/', 'https://chao.fang.anjuke.com/',
                  'https://cx.fang.anjuke.com/', 'https://hf.fang.anjuke.com/', 'https://changd.fang.anjuke.com/',
                  'https://cg.fang.anjuke.com/', 'https://chongz.fang.anjuke.com/', 'https://chss.fang.anjuke.com/',
                  'https://ba.fang.anjuke.com/', ]

    def parse(self, response):
        divs = response.xpath('''//div[@class="key-list imglazyload"]/div''')  # 使用xpath從response中獲取需要的html塊
        city = response.xpath(
            '''//span[@class="city"]/text()''').extract_first()  # 我們匹配到的其實只有一個,獲取第一個就行了,這里如果用.extract()其實會返回一個列表
        print(divs)
        for div in divs:

            item = AnjukeItem()  # 實例化item對象
            item['city'] = city  # 城市
            item['address'] = div.xpath('.//span[@class="list-map"]/text()').extract_first()  # 樓盤地址
            item['name'] = div.xpath('.//span[@class="items-name"]/text()').extract_first()  # 開發商名稱
            try:
                item['type_'] = div.xpath('.//a[@class="huxing"]/span/text()').extract()[:-1]  # 房子類型比如兩房一廳這樣子~
            except:
                pass

            item['tags'] = div.xpath('.//span[@class="tag"]/text()').extract()  # 網站給樓盤定的標簽~

            price = div.xpath('.//p[contains(@class,"price")]//text()').extract()  # 價格
            item['price'] = price
            try:

                item['area'] = div.xpath('.//a[@class="huxing"]/span/text()').extract()[-1].replace('建築面積:',
                                                                                                    '')  # 房子面積范圍~
            except:
                pass
            yield item

        next_ = response.xpath('//a[@class="next-page next-link"]/@href').extract_first()  # 獲取下一頁的鏈接
        print('-----next')
        print(next_)
        yield response.follow(url=next_, callback=self.parse)  # 將下一頁的鏈接加入爬取隊列~~
上面的start_urls的鏈接是另外爬的,鏈接這里:安居客,全部鏈接爬下來了,這里為了篇幅就列出幾個就好了。

 

上面代碼item的結構:

為什么我要將價格保存為list呢?

因為網站這里給的價格有最低價、總價、均價,我只想要均價,保留價格的類型后面用時分類方便~

然后是將數據保存到Mongodb,需要對pipelines.py進行一些修改:

import pymongo


class TextPipeline(object):  #這個自定義的類是打算用來處理item數據的,后來發現爬到的item數據好像還挺干凈就沒有寫邏輯了~
    def process_item(self, item, spider):
        print(item)
        return item


class MongoPipeline(object):
    def __init__(self,mongo_uri,mongo_db):  
        self.mongo_uri = mongo_uri
        self.mongo_db = mongo_db
    @classmethod
    def from_crawler(cls,crawler):  #類方法,用於從settins.py中獲取在那邊設置的MONGO_URI和MONGO_DB
        return cls(
            mongo_uri = crawler.settings.get('MONGO_URI'),
            mongo_db = crawler.settings.get('MONGO_DB')
            )
    def open_spider(self,spider):  #當spider開啟時這個方法被調用,這里用來連接數據庫
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client[self.mongo_db]
    def process_item(self,item,spider):  #實現了item數據插入到數據庫,自動創建與項目名同名,spider同名的表,數據都保存在里面
        name = item.__class__.__name__
        self.db[name].insert(dict(item))
        return item
    def close_spider(self,spider):  #當spider關閉時這個方法被調用
        self.client.close()

 

最后就是應付反爬的一些操作咯:

這些都在settings.py設置:

首先,站點對user-agent有檢查,發現是爬蟲頭直接跳轉到驗證碼頁面...

emmm,偽造瀏覽器請求頭就好了:

在settings.py加(記得import random):

USER_AGENT_LIST=[  #各瀏覽器的請求頭
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36'
    "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
    "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
    "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
    "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
]
USER_AGENT = random.choice(USER_AGENT_LIST)  #隨機從上面列表中選取請求頭,偽造請求頭~

還有就是禁用cookie,網站會通過用戶的Cookie信息對用戶進行識別與分析,所以要防止目標網站識別我們的會話信息:

COOKIES_ENABLED = False  #關閉cookie

最后就是訪問頻率的控制,站點對一個ip的訪問頻率也有監測,一直很訪問快的話,也是會跳到人機驗證頁面~:

DOWNLOAD_DELAY = random.choice([1,2])  #訪問延時,隨機選1或2~

 最后,看看爬到的部分數據(去重之后大概有7w條左右)~

 

對爬取到的數據的想法:

1、給出的房源少,房源最多的城市也就2000左右,我想這很大程度並不能代表各個城市的平均水平。。

2、爬到的數據也不一定對,可能房地產或網站這邊故意壓低一點房價,以消費者吸引目光~

3、其實最好的辦法是以公司的合作來取到數據,有這樣官方的數據就不用自己去爬了,而且也最准確、最真實啊(有大腿抱得話真的舒服)~

 

End


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM