爬取房天下二手房數(shù)據(jù)和二手房房價分析及預測

第一部分 爬蟲

  1. 數(shù)據(jù)來源:房天下
  2. 網(wǎng)頁結構分析
  • 通過抓包分析網(wǎng)頁信息,房源信息就是包含在當前HTML文件中。
  • 目標URL規(guī)律:

第一頁:https://lz.esf.fang.com/house/i31/
第二頁:https://lz.esf.fang.com/house/i32/
第三頁:https://lz.esf.fang.com/house/i33/
......
第十頁:https://lz.esf.fang.com/house/i310/
從中可以看出,變化的只是最后面的一部分,那么實現(xiàn)多頁爬取時構造新的URL就比較容易。(拼接頁數(shù)就可以)

  1. 爬取內(nèi)容分析
    為了得到更多的有用信息,需要進行詳情頁的跳轉(zhuǎn),也就是說,首先獲取詳情頁鏈接,然后在請求獲取房源信息。


    info1.png

    info2.png
  2. 難點

  • 重定向

當興高采烈的拿著地址去訪問的時候,返回信息如下,臉黑了,說明發(fā)生了重定向問題。在請求該地址后,會出現(xiàn)短暫的“跳轉(zhuǎn)”字眼。


跳轉(zhuǎn).png

那么我們就在這個網(wǎng)頁信息里查找下一個請求地址,如下圖可以看到點擊跳轉(zhuǎn)前有我們想要的信息,這是目標網(wǎng)頁請求地址。


點擊跳轉(zhuǎn).png

在進行詳情頁跳轉(zhuǎn)的時候也存在這個問題,分析思路是一樣的。
  • 驗證碼

selenium + 云打碼平臺解決或者人工輸入

  1. 爬取思路


    過程.png
  2. 代碼實現(xiàn)

  • 詳情頁地址
#!/user/bin/env python3
# -*- coding: utf-8 -*-

import requests
# 自定義的UA庫
from UA import ua
import random
from lxml import etree
import time
from requests.packages.urllib3.exceptions import InsecureRequestWarning
from selenium import webdriver

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

headers = {'User-Agent': ''}

def get_detail_url(url):

    headers['User-Agent'] = random.choice(ua)
    try:
        r = requests.get(url, headers=headers, verify=False)
        html = etree.HTML(r.text)
        # 經(jīng)過上述跳轉(zhuǎn),得到目標網(wǎng)頁地址
        roal_url = html.xpath('//a[@class="btn-redir"]/@href')[0]
        r = requests.get(roal_url, headers=headers, verify=False)
        html = etree.HTML(r.text)
        hrefs = html.xpath('//div[@class="shop_list shop_list_4"]/dl/dt/a/@href')
        channels = html.xpath('//div[@class="shop_list shop_list_4"]/dl/dt/a/@data_channel')
        next_urls = ['https://lz.esf.fang.com' + href +'?channel=' + channel for href,channel in zip(hrefs,channels)]
        house.extend(next_urls)
    except:
        process_captcha()
        get_detail_url(url)

def process_captcha():

    # 該處url是讓出現(xiàn)驗證碼界面,沒有具體的限制
    url = 'https://lz.esf.fang.com/chushou/3_416752691.htm?channel=2,2'
    driver = webdriver.Firefox()
    driver.get(url)
    # 人工輸入驗證碼
    time.sleep(12)
    driver.find_element_by_name('submit').click()
    driver.close()

if __name__ == '__main__':

    '''
   這個過程中,貌似只能爬取100頁,那么可以細化,比如分區(qū)域爬取,可以再細分。
    '''
    house = []
    for i in range(1,100):
        print('--------------------------------')
        print(f'開始爬取第{i}頁')
        url = f'https://lz.esf.fang.com/house/i3{i}/'
        get_detail_url(url)
    print('爬取結束!')
    f = open('urls.txt', 'a+', encoding='utf8')
    for i in house:
        f.write(i + '\n')
    f.close()
  • 房屋信息
#!/user/bin/env python3
# -*- coding: utf-8 -*-

import requests
from UA import ua
import random
from lxml import etree
import time
from requests.packages.urllib3.exceptions import InsecureRequestWarning
import csv
from selenium import webdriver
from PIL import Image
# 云打碼平臺API
from vcode import *

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

headers = {'User-Agent': ''}

def get_info(url):

    headers['User-Agent'] = random.choice(ua)
    # 解決驗證碼反爬蟲問題
    try:
        r = requests.get(url, headers=headers, verify=False, timeout=60)
        html = etree.HTML(r.text)
        detail_url = html.xpath('//a[@class="btn-redir"]/@href')[0]
        r = requests.get(detail_url, headers=headers, verify=False, timeout=60)
        html = etree.HTML(r.text)
        total_price = html.xpath('//div[@class="tab-cont-right"]/div[1]/div[1]/div[1]/i/text()')[0]
        style = html.xpath('//div[@class="tab-cont-right"]/div[@class="tr-line clearfix"][1]/div[1]/div[1]/text()')[
            0].replace('\n', '').strip()
        area = html.xpath('//div[@class="tab-cont-right"]/div[@class="tr-line clearfix"][1]/div[2]/div[1]/text()')[0]
        unit_price = \
        html.xpath('//div[@class="tab-cont-right"]/div[@class="tr-line clearfix"][1]/div[3]/div[1]/text()')[0]
        direction = html.xpath('//div[@class="tab-cont-right"]/div[@class="tr-line clearfix"][2]/div[1]/div[1]/text()')[
            0]
        floor = html.xpath('//div[@class="tab-cont-right"]/div[@class="tr-line clearfix"][2]/div[2]/div[1]/text()')[0]
        decoration = \
        html.xpath('//div[@class="tab-cont-right"]/div[@class="tr-line clearfix"][2]/div[3]/div[1]/text()')[0]
        local = html.xpath('//div[@class="tab-cont-right"]/div[@class="tr-line"]/div[2]/div[2]/a[1]/text()')[0].replace(
            '\n', '').strip()
        school = html.xpath('//div[@class="tab-cont-right"]/div[@class="tr-line"]/div[3]')
        if len(school):
            school = 1
        else:
            school = 0
        data = {'總價': total_price,
                '戶型': style,
                '建筑面積': area,
                '單價': unit_price,
                '朝向': direction,
                '樓層': floor,
                '裝修': decoration,
                '區(qū)域': local,
                '學校': school}
        content = {'建筑年代': '',
                   '有無電梯': '',
                   '產(chǎn)權性質(zhì)': '',
                   '住宅類別': '',
                   '建筑結構': '',
                   '建筑類別': ''}
        info = html.xpath('//div[@class="content-item fydes-item"]/div[2]//span/text()')
        for i in range(int((len(info) - 2) / 2)):
            content[info[2 * i]] = info[2 * i + 1]
        to_csv(data, content)
    except:
        title = process_captcha(url)
        # 檢驗url是否有效,推測原因是房源信息已經(jīng)不存在了,
        # 如果存在,則重新請求,反之,就結束當前請求,開始下一個請求
        if title == '蘭州二手房-房天下':
            delete.append(url)
            pass
        else:
            # 防止一個請求循環(huán)進行,導致一直使用驗證碼平臺,進行下一個
            if url in flag:
                return
            flag.append(url)
            get_info(url)

def to_csv(data,content):
    with open('house.csv', 'a+', encoding='utf-8', newline='') as f:
        writer = csv.writer(f)
        writer.writerow([data['戶型'], data['建筑面積'], data['朝向'], data['樓層'], data['裝修'],
                        content['建筑年代'], content['有無電梯'], content['產(chǎn)權性質(zhì)'], content['住宅類別'],
                        content['建筑結構'], content['建筑類別'], data['區(qū)域'],
                        data['學校'], data['總價'], data['單價']])

def process_captcha(url):

    driver = webdriver.Firefox()
    driver.get(url)
    print(url)
    driver.save_screenshot('code.png')
    left = 700
    top = 340
    right = 900
    bottom = 405
    im = Image.open('code.png')
    im = im.crop((left, top, right, bottom))
    im.save('captcha.png')
    # 實例化,需要自己的賬號、密碼、驗證碼對應類型
    cjy = Chaojiying_Client(你的賬號,你的密碼, '902223')
    im = open('captcha.png', 'rb').read()
    code = cjy.PostPic(im,1004).get('pic_str')
    driver.find_element_by_id('code').send_keys(code)
    time.sleep(1)
    driver.find_element_by_name('submit').click()
    time.sleep(2)
    driver.get(url)
    title = driver.title
    driver.close()
    return title

if __name__ == '__main__':

    house = []
    f = open('urls.txt')
    texts = f.readlines()
    for text in texts:
        house.append(text.rstrip())
    house = list(set(house))
    f.close()
    delete = []
    flag = []
    for i in range(2852,len(house)):
        print(f'開始爬取第{i+1}條信息')
        get_info(house[i])
    print('爬取結束!')
  1. 結果展示


    結果.png

    共計將近8000多條數(shù)據(jù),和下圖對應。


    總體情況.png
  2. 數(shù)據(jù)詳情見:https://www.kesci.com/home/dataset/5f073e5ac94d2e002d03522d/files

二、數(shù)據(jù)分析

項目詳情見:https://www.kesci.com/home/project/5f098536192ac2002c87c5aa

每天進步一點點!

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容