做者:xiaoyuhtml
微信公衆號:Python數據科學前端
知乎:python數據分析師python
前一段時間與你們分享了北京二手房房價分析的實戰項目,分爲分析和建模兩篇。文章發出後,獲得了你們的確定和支持,在此表示感謝。json
除了數據分析,好多朋友也對爬蟲特別感興趣,想知道爬蟲部分是如何實現的。本篇將分享這個項目的爬蟲部分,算是數據分析的一個 前傳篇。微信
爬蟲部分主要是經過爬取鏈x和安x客來獲取二手房住房信息,由於考慮到不一樣網站的房源信息能夠互補,因此選擇了兩個網站。框架
爬取目標是北京二手房,僅針對一個城市而言,數據量並不大。因此直接採用Scrapy
來完成爬取工做,而後將數據存儲在csv格式的文件中。最終爬取結果是這樣的,鏈x的爬蟲爬取了 30000+
條數據,安x客的爬蟲爬取了 3000+
條數據。不得不說鏈x的房源相對來說仍是比較全的。異步
寫一個爬蟲最開始固然要想清楚須要獲取什麼樣的數據了。本次項目對與二手房相關的數據都比較感興趣,能夠天然的想到,每一個房源連接的具體詳細信息是最全的。但考慮到爬蟲深度影響總體爬蟲效率問題,而且房源列表中數據已經可以知足基本的要求,並無必要對每一個詳細連接進行深刻的爬取,所以最終選擇爬取房源列表。如下是房源列表(部分截圖)中的房源信息:scrapy
肯定以上爬取內容後,就開始爬蟲部分的工做。首先在item.py
文件中定義一個子類,該子類繼承了父類scrapy.Item
,而後在子類中用scrapy.Field()
定義以上信息的字段。以下代碼,將全部須要的字段信息都設置好。ide
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文件夾下的爬取文件(自定義)中導入所需庫,以下代碼:函數
# -*- 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
回調逐層實現解析功能,這三個函數是:
下面是三個函數的功能描述,以及代碼實現。
任何爬蟲都須要有初始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)
對每一個大區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函數中,首先經過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,每組位置下包含相關字段信息。
這裏說的位置不一樣是在前端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爬取部分的思想一致,不一樣的是使用了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數據科學,發現更多精彩內容。