国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

作為前端,如何幫帝都的朋友租到合適的房子

pubdreamcc / 2297人閱讀

摘要:前后翻幾頁(yè)我們不難發(fā)現(xiàn),豆瓣是利用后面的參數(shù)來(lái)實(shí)現(xiàn)分頁(yè)的。最后我們打開(kāi)看一看效果吧,標(biāo)紅的是回復(fù)數(shù)量,點(diǎn)擊標(biāo)題可以直接跳轉(zhuǎn)到豆瓣對(duì)應(yīng)的頁(yè)面。

??在帝都打拼的小伙伴都知道,要租個(gè)合適的房子真心不易。中介要收一個(gè)月的房租作為中介費(fèi)。而且很多黑中介打著租房的旗號(hào)各種坑蒙拐騙。要想在茫茫帖子中找到真正的房東,宛如大海撈針,同時(shí)需要和各路黑中介斗智斗勇。接下來(lái)就講講我浴血奮戰(zhàn)的故事。

??那么,How to start? 我們先選一塊陣地。58趕集這樣的網(wǎng)站,可以說(shuō)中介占了大多數(shù),地勢(shì)險(xiǎn)峻,易守難攻,果斷放棄。閑魚(yú)呢,資源又太少,攻下來(lái)的意義也不大,所以也放棄。我把目標(biāo)放在了豆瓣上。在帝都的童鞋大部分都知道,豆瓣小組里面有很多租房小組,年輕人居多,很多都是轉(zhuǎn)租,但很大一部分是和房東簽的合同,省掉了中介費(fèi)。我大致翻了一下,基本上一天內(nèi)的更新量能刷到90頁(yè),每頁(yè)25條數(shù)據(jù),當(dāng)然有一些是舊的被頂上來(lái)的。這個(gè)數(shù)據(jù)量已經(jīng)不少了,雖然里面也混雜著大量的中介,但是相對(duì)來(lái)說(shuō)比其他地方好很多。

鄭重聲明:各位在爬取數(shù)據(jù)的時(shí)候一定要控制頻率,不要影響網(wǎng)站的正常訪(fǎng)問(wèn)!而且頻率過(guò)高會(huì)被豆瓣干掉,且爬且珍惜!
另外,請(qǐng)?jiān)敿?xì)閱讀注釋中的內(nèi)容!

??我們先分析一下要抓取頁(yè)面的結(jié)構(gòu)。以大名鼎鼎的北京租房小組舉例。


??首先我們點(diǎn)擊下方的更多小組討論切換到列表頁(yè)面,這樣就可以分析頁(yè)面的分頁(yè)邏輯了。前后翻幾頁(yè)我們不難發(fā)現(xiàn),豆瓣是利用url后面的參數(shù)來(lái)實(shí)現(xiàn)分頁(yè)的。比如第一頁(yè)的url為https://www.douban.com/group/beijingzufang/discussion?start=0,第二頁(yè)為https://www.douban.com/group/beijingzufang/discussion?start=25,每頁(yè)25條數(shù)據(jù),很清晰明了了吧?

??這時(shí)候,我們只需要分別獲取到每頁(yè)的數(shù)據(jù),然后再做一些過(guò)濾,就可以極大減少篩選的時(shí)間了。我們選擇前二十個(gè)頁(yè)面來(lái)作為爬取對(duì)象,一方面不會(huì)對(duì)網(wǎng)站造成影響,另一方面也保證數(shù)據(jù)盡可能使最新。

??好的,重點(diǎn)來(lái)了,作為一個(gè)前端,我使用node來(lái)做抓取,先引入一些必要的依賴(lài)。

import fs from "fs"    // node的文件模塊,用于將篩選后的數(shù)據(jù)輸出為html
import path from "path" // node的路徑模塊,用于處理文件的路徑

//  以下模塊非node.js自帶模塊,需要使用npm安裝

// 客戶(hù)端請(qǐng)求代理模塊
import superagent from "superagent"   
// node端操作dom的利器,可以理解成node版jQuery,語(yǔ)法與jQuery幾乎一樣
import cheerio from "cheerio"   
// 通過(guò)事件來(lái)決定執(zhí)行順序的工具,下面用到時(shí)作詳解
import eventproxy from "eventproxy" 
//  async是一個(gè)第三方node模塊,mapLimit用于控制訪(fǎng)問(wèn)頻率
import mapLimit from "async/mapLimit"  

??然后就可以把我們要抓取的頁(yè)面整理到一個(gè)數(shù)組里面了

let ep = new eventproxy()  //  實(shí)例化eventproxy

let baseUrl = "https://www.douban.com/group/beijingzufang/discussion?start=";  
let pageUrls = []  // 要抓取的頁(yè)面數(shù)組

let page = 20  // 抓取頁(yè)面數(shù)量
let perPageQuantity = 25   //  每頁(yè)數(shù)據(jù)條數(shù)

for (let i = 0; i < page; i++) {
  pageUrls.push({
    url: baseUrl + i * perPageQuantity
  });
}

??簡(jiǎn)單分析下頁(yè)面的dom結(jié)構(gòu)。頁(yè)面中的有效數(shù)據(jù)全在table中,第一個(gè)tr是標(biāo)題,接下來(lái)每個(gè)tr對(duì)應(yīng)一條數(shù)據(jù)。然后每個(gè)tr下有4個(gè)td。分別存放著標(biāo)題,作者,回應(yīng)數(shù)和最后修改時(shí)間。

??我們先寫(xiě)個(gè)入口函數(shù),訪(fǎng)問(wèn)所有要抓取的頁(yè)面并保存我們需要的數(shù)據(jù)。話(huà)說(shuō),好久不寫(xiě)jQuery都有點(diǎn)手生了。

function start() {
  //  遍歷爬取頁(yè)面
  const getPageInfo = (pageItem, callback) => {
    //  設(shè)置訪(fǎng)問(wèn)間隔
    let delay = parseInt((Math.random() * 30000000) % 1000, 10)
    pageUrls.forEach(pageUrl => {
      superagent.get(pageUrl.url)
        // 模擬瀏覽器
        .set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36") 
        //  如果你不乖乖少量爬數(shù)據(jù)的話(huà),很可能被豆瓣kill掉,這時(shí)候需要模擬登錄狀態(tài)才能訪(fǎng)問(wèn)
        // .set("Cookie","")  
        .end((err, pres) => {
          let $ = cheerio.load(pres.text) // 將頁(yè)面數(shù)據(jù)用cheerio處理,生成一個(gè)類(lèi)jQuery對(duì)象

          let itemList = $(".olt tbody").children().slice(1, 26) // 取出table中的每行數(shù)據(jù),并過(guò)濾掉表格標(biāo)題

          // 遍歷頁(yè)面中的每條數(shù)據(jù)
          for (let i = 0; i < itemList.length; i++) {
            let item = itemList.eq(i).children()

            let title = item.eq(0).children("a").text() || "" // 獲取標(biāo)題
            let url = item.eq(0).children("a").attr("href") || "" // 獲取詳情頁(yè)鏈接
            // let author = item.eq(1).children("a").attr("href").replace("https://www.douban.com/people", "").replace(///g, "") || ""  // 獲取作者id
            let author = item.eq(1).children("a").text() || "" // 這里改為使用作者昵稱(chēng)而不是id的原因是發(fā)現(xiàn)有些中介注冊(cè)了好多賬號(hào),打一槍換個(gè)地方。雖然同名也有,但是這么小的數(shù)據(jù)量下,概率低到忽略不計(jì)
            let markSum = item.eq(2).text() // 獲取回應(yīng)數(shù)量
            let lastModify = item.eq(3).text() // 獲取最后修改時(shí)間

            let data = {
              title,
              url,
              author,
              markSum,
              lastModify
            }
            // ep.emit("事件名稱(chēng)", 數(shù)據(jù)內(nèi)容)
            ep.emit("preparePage", data) // 每處理完一條數(shù)據(jù),便把這條數(shù)據(jù)通過(guò)preparePage事件發(fā)送出去,這里主要是起計(jì)數(shù)的作用
          }
          setTimeout(() => {
            callback(null, pageItem.url);
          }, delay);
        })
    })
  }
}

??我們通過(guò)mapLimit來(lái)控制訪(fǎng)問(wèn)頻率,mapLimit的細(xì)節(jié)參照官方文檔。傳送門(mén)

  mapLimit(pageUrls, 2, function (item, callback) {
    getPageInfo(item, callback);
  }, function (err) {
    if (err) {
      console.log(err)
    }
    console.log("抓取完畢")
  });

??簡(jiǎn)單說(shuō)一下過(guò)濾的策略吧,首先在標(biāo)題里,過(guò)濾掉不合適的地點(diǎn),以及中介最常用的話(huà)術(shù)。也可以自己添加想要的關(guān)鍵詞,有針對(duì)性的進(jìn)行篩選。然后統(tǒng)計(jì)每個(gè)作者的發(fā)帖數(shù),這里的判斷條件是如果每個(gè)人發(fā)帖數(shù)在抓取的頁(yè)面中出現(xiàn)超過(guò)5次以上,則被認(rèn)為是中介。如果某個(gè)帖子的回復(fù)量巨大,要么是個(gè)舊帖子被頂上來(lái)了,要么很可能是有人在不停的刷排名,我這里設(shè)置的閾值是100。試想一個(gè)正常的房東不會(huì)這么喪心病狂的刷存在感,因?yàn)楹梅扛静怀钭獠怀鋈ィ芸赡苁侵薪槊刻煸谒⑴f帖子。即便是因?yàn)榉孔颖容^好所以大家都在圍觀,那其實(shí)你租到的概率已經(jīng)很小了,所以直接過(guò)濾掉。

//  我們?cè)O(shè)置三個(gè)全局變量來(lái)保存一些數(shù)據(jù)
let result = []   //  存放最終篩選結(jié)果
let authorMap = {} // 我們以對(duì)象屬性的方式,來(lái)統(tǒng)計(jì)每個(gè)的發(fā)帖數(shù)
let intermediary = [] // 中介id列表,你也可以把這部分?jǐn)?shù)據(jù)保存起來(lái),以后抓取的時(shí)候直接過(guò)濾掉!

// 還記得之前的ep.emit()嗎,它的每次emit都被這里捕獲。ep.after("事件名稱(chēng)",數(shù)量,事件達(dá)到指定數(shù)量后的callback())。
// 也就是說(shuō),總共有20*25(頁(yè)面數(shù)*每頁(yè)數(shù)據(jù)量)個(gè)事件都被捕獲到以后,才會(huì)執(zhí)行這里的回調(diào)函數(shù)
ep.after("preparePage", pageUrls.length * page, function (data) {
    // 這里我們傳入不想要出現(xiàn)的關(guān)鍵詞,用"|"隔開(kāi) 。比如排除一些位置,排除中介常用短語(yǔ)
    let filterWords = /押一付一|短租|月付|蛋殼|有房出租|6號(hào)線(xiàn)|六號(hào)線(xiàn)/ 
    // 這里我們傳入需要篩選的關(guān)鍵詞,如沒(méi)有,可設(shè)置為空格
    let keyWords = /西二旗/
    
    // 我們先統(tǒng)計(jì)每個(gè)人的發(fā)帖數(shù),并以對(duì)象的屬性保存。這里利用對(duì)象屬性名不能重復(fù)的特性實(shí)現(xiàn)計(jì)數(shù)。
    data.forEach(item => {
      authorMap[item.author] = authorMap[item.author] ? ++authorMap[item.author] : 1
      if (authorMap[item.author] > 4) {
        intermediary.push(item.author) // 如果發(fā)現(xiàn)某個(gè)人的發(fā)帖數(shù)超過(guò)5條,直接打入冷宮。
      }
    })
    // 數(shù)組去重,Set去重了解一下,可以查閱Set這種數(shù)據(jù)結(jié)構(gòu)
    intermediary = [...new Set(intermediary)]
    // 再次遍歷抓取到的數(shù)據(jù)
    data.forEach(item => {
    //  這里if的順序可是有講究的,合理的排序可以提升程序的效率
      if (item.markSum > 100) {
        console.log("評(píng)論過(guò)多,丟棄")
        return
      }
      if (filterWords.test(item.title)) {
        console.log("標(biāo)題帶有不希望出現(xiàn)的詞語(yǔ)")
        return
      }
      if(intermediary.includes(item.author)){
        console.log("發(fā)帖數(shù)過(guò)多,丟棄")
        return
      }
      //  只有通過(guò)了上面的層層檢測(cè),才會(huì)來(lái)到最后一步,這里如果你沒(méi)有設(shè)期望的關(guān)鍵詞,篩選結(jié)果會(huì)被統(tǒng)統(tǒng)加到結(jié)果列表中
      if (keyWords.test(item.title)) {
        result.push(item)
      }
    })
    
    // .......
});

??到此為止,我們已經(jīng)拿到了期望的結(jié)果列表,但是直接打印出來(lái),并不那么的好用,所以我們把它生成一個(gè)html。我們只需簡(jiǎn)單的進(jìn)行html的拼裝即可

//  設(shè)置html模板
let top = "" +
      "" +
      "" +
      "" +
      "" +
      "篩選結(jié)果" +
      "" +
      "" +
      "
" let bottom = "
" // 拼裝有效數(shù)據(jù)html let content = "" result.forEach(function (item) { content += `${item.title}_____${item.markSum}____${item.lastModify}` }) let final = top + content + bottom // 最后把生成的html輸出到指定的文件目錄下 fs.writeFile(path.join(__dirname, "../tmp/result.html"), final, function (err) { if (err) { return console.error(err); } console.log("success") });

??最后,我們只需把入口函數(shù)暴露出去即可

export default {
  start
}

??由于我們是使用ES6的語(yǔ)法寫(xiě)的,所以在使用的時(shí)候,需要借助babel-node。首先安裝babel-cli,你可以選擇全局安裝或者局部安裝, npm i babel-cli -g。同時(shí)別忘了文章開(kāi)頭三個(gè)依賴(lài)的安裝。

??最終我們?cè)趇ndex.js文件中引入上面的腳本,并執(zhí)行babel-node index.js。我們看到了激動(dòng)人心的success。

// index.js
import douban from "./src/douban.js"
douban.start()

??最后我們打開(kāi)HTML看一看效果吧,標(biāo)紅的是回復(fù)數(shù)量,點(diǎn)擊標(biāo)題可以直接跳轉(zhuǎn)到豆瓣對(duì)應(yīng)的頁(yè)面。同時(shí),利用a標(biāo)簽點(diǎn)擊過(guò)后變色的效果,我們可以方便的判斷是否已經(jīng)看過(guò)這條數(shù)據(jù)。

??我簡(jiǎn)單設(shè)置了一些過(guò)濾條件,數(shù)據(jù)由500條直線(xiàn)下降到138條,極大的縮短了我們的篩選時(shí)間。如果我加一些指定的篩選關(guān)鍵詞,搜索結(jié)果還會(huì)更精準(zhǔn)!

??好了,時(shí)候不早了,今天的分享就到此為止。如果大家覺(jué)得找房子比較費(fèi)勁,還是要去找鏈家,我愛(ài)我家等這樣的大中介,比較靠譜省心。最后祝大家找到暖心的小窩!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/113433.html

相關(guān)文章

  • 作為前端如何帝都朋友租到合適房子

    摘要:前后翻幾頁(yè)我們不難發(fā)現(xiàn),豆瓣是利用后面的參數(shù)來(lái)實(shí)現(xiàn)分頁(yè)的。最后我們打開(kāi)看一看效果吧,標(biāo)紅的是回復(fù)數(shù)量,點(diǎn)擊標(biāo)題可以直接跳轉(zhuǎn)到豆瓣對(duì)應(yīng)的頁(yè)面。 ??在帝都打拼的小伙伴都知道,要租個(gè)合適的房子真心不易。中介要收一個(gè)月的房租作為中介費(fèi)。而且很多黑中介打著租房的旗號(hào)各種坑蒙拐騙。要想在茫茫帖子中找到真正的房東,宛如大海撈針,同時(shí)需要和各路黑中介斗智斗勇。接下來(lái)就講講我浴血奮戰(zhàn)的故事。 ??那么...

    xiaolinbang 評(píng)論0 收藏0
  • 高德API+Python解決租房問(wèn)題

    摘要:本教程由發(fā)布在實(shí)驗(yàn)樓,完整教程及在線(xiàn)練習(xí)地址高德解決租房問(wèn)題,可以直接在教程中下載代碼使用。本課程將解決的問(wèn)題學(xué)習(xí)了技術(shù),增長(zhǎng)了知識(shí),就能找到好工作,找到好工作就能有錢(qián)。 項(xiàng)目簡(jiǎn)介:編寫(xiě)Python腳本爬取某租房網(wǎng)站的房源信息,利用高德的 js API 在地圖上標(biāo)出房源地點(diǎn),劃出距離工作地點(diǎn)1小時(shí)內(nèi)可到達(dá)的范圍,附上公交路徑規(guī)劃功能查看不同路徑的用時(shí)。 本教程由ekCit發(fā)布在實(shí)驗(yàn)樓,...

    dreamtecher 評(píng)論0 收藏0
  • 回望2017:一個(gè)前端從業(yè)者砥礪前行一年

    摘要:走過(guò)了這一年,公眾號(hào)的名稱(chēng)前前后后改了三次,最后定格為閏土大叔。均價(jià),這價(jià)格絕對(duì)屬于太原市最便宜的樓盤(pán)之一了。據(jù)售樓部的朋友說(shuō),未來(lái)兩年太原的房?jī)r(jià)還會(huì)迎來(lái)新一波的漲價(jià)潮,到了年,太原會(huì)承辦全國(guó)青少年運(yùn)動(dòng)會(huì),簡(jiǎn)稱(chēng)青運(yùn)會(huì)。 前言 從年前就嚷嚷著要走出去走出去,轉(zhuǎn)眼間已經(jīng)到了年底依然在我的大太原呆著。年底了,不能免俗的我,也來(lái)寫(xiě)一篇2017年度工作總結(jié)的文章,湊湊熱鬧。如果對(duì)你有一點(diǎn)點(diǎn)啟發(fā),...

    dmlllll 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<