node爬蟲入門竟如此簡單

前言

爬蟲一直是軟件工程師里看起來比較神秘高深的一門學(xué)問,它讓人們想起黑客,以及SEO等等。
目前市面上也有專門的爬蟲工程師,并且在大企業(yè)的大數(shù)據(jù)部門,大數(shù)據(jù)工程師們也會(huì)兼任一些爬取競對(duì)數(shù)據(jù)的工作,當(dāng)然也有專門做安全的工程師應(yīng)對(duì)爬蟲的危害。所以爬蟲真的那么高深莫測(cè)嗎?下面就來揭開它的神秘面紗,帶你入門node爬蟲!


我們的目標(biāo)是:爬取鏈家官網(wǎng)租房市場(chǎng)相關(guān)數(shù)據(jù),并形成可視化圖表

最終成果

在這之前,我們先普及一些爬蟲的相關(guān)知識(shí):

爬蟲的概念

網(wǎng)絡(luò)爬蟲(Web crawler),是一種按照一定的規(guī)則,自動(dòng)地抓取萬維網(wǎng)信息的程序或者腳本。(百度百科)

爬蟲的分類

通用網(wǎng)絡(luò)爬蟲(全網(wǎng)爬蟲)
爬行對(duì)象從一些 種子URL 擴(kuò)充到整個(gè) Web,主要為門戶站點(diǎn)搜索引擎和大型 Web 服務(wù)提供商采集數(shù)據(jù)。
聚焦網(wǎng)絡(luò)爬蟲(主題網(wǎng)絡(luò)爬蟲)
是 指選擇性 地爬行那些與預(yù)先定義好的主題相關(guān)頁面的網(wǎng)絡(luò)爬蟲。
增量式網(wǎng)絡(luò)爬蟲
指對(duì)已下載網(wǎng)頁采取增量式更新和只爬行新產(chǎn)生的或者已經(jīng)發(fā)生變化網(wǎng)頁 的爬蟲,它能夠在一定程度上保證所爬行的頁面是盡可能新的頁面。
Deep Web 爬蟲
爬行對(duì)象是一些在用戶填入關(guān)鍵字搜索或登錄后才能訪問到的深層網(wǎng)頁信息的爬蟲。

爬蟲工作原理

工作原理

從種子URL進(jìn)入,獲取待抓取URL隊(duì)列,再進(jìn)入各URL網(wǎng)頁,進(jìn)行信息抓取并存儲(chǔ),對(duì)隊(duì)列進(jìn)行入隊(duì)和出隊(duì)操作。

爬蟲的爬行及反爬策略

爬行策略

網(wǎng)頁的抓取策略可以分為深度優(yōu)先、廣度優(yōu)先和最佳優(yōu)先三種。深度優(yōu)先在很多情況下會(huì)導(dǎo)致爬蟲的陷入(trapped)問題,目前常見的是廣度優(yōu)先和最佳優(yōu)先方法。

  • 廣度優(yōu)先
    廣度優(yōu)先搜索策略是指在抓取過程中,在完成當(dāng)前層次的搜索后,才進(jìn)行下一層次的搜索。該算法的設(shè)計(jì)和實(shí)現(xiàn)相對(duì)簡單。在目前為覆蓋盡可能多的網(wǎng)頁,一般使用廣度優(yōu)先搜索方法。也有很多研究將廣度優(yōu)先搜索策略應(yīng)用于聚焦爬蟲中。其基本思想是認(rèn)為與初始URL在一定鏈接距離內(nèi)的網(wǎng)頁具有主題相關(guān)性的概率很大。另外一種方法是將廣度優(yōu)先搜索與網(wǎng)頁過濾技術(shù)結(jié)合使用,先用廣度優(yōu)先策略抓取網(wǎng)頁,再將其中無關(guān)的網(wǎng)頁過濾掉。這些方法的缺點(diǎn)在于,隨著抓取網(wǎng)頁的增多,大量的無關(guān)網(wǎng)頁將被下載并過濾,算法的效率將變低。
  • 最佳優(yōu)先
    最佳優(yōu)先搜索策略按照一定的網(wǎng)頁分析算法,預(yù)測(cè)候選URL與目標(biāo)網(wǎng)頁的相似度,或與主題的相關(guān)性,并選取評(píng)價(jià)最好的一個(gè)或幾個(gè)URL進(jìn)行抓取。它只訪問經(jīng)過網(wǎng)頁分析算法預(yù)測(cè)為“有用”的網(wǎng)頁。存在的一個(gè)問題是,在爬蟲抓取路徑上的很多相關(guān)網(wǎng)頁可能被忽略,因?yàn)樽罴褍?yōu)先策略是一種局部最優(yōu)搜索算法。因此需要將最佳優(yōu)先結(jié)合具體的應(yīng)用進(jìn)行改進(jìn),以跳出局部最優(yōu)點(diǎn)。將在第4節(jié)中結(jié)合網(wǎng)頁分析算法作具體的討論。研究表明,這樣的閉環(huán)調(diào)整可以將無關(guān)網(wǎng)頁數(shù)量降低30%~90%。
  • 深度優(yōu)先
    深度優(yōu)先搜索策略從起始網(wǎng)頁開始,選擇一個(gè)URL進(jìn)入,分析這個(gè)網(wǎng)頁中的URL,選擇一個(gè)再進(jìn)入。如此一個(gè)鏈接一個(gè)鏈接地抓取下去,直到處理完一條路線之后再處理下一條路線。深度優(yōu)先策略設(shè)計(jì)較為簡單。然而門戶網(wǎng)站提供的鏈接往往最具價(jià)值,PageRank也很高,但每深入一層,網(wǎng)頁價(jià)值和PageRank都會(huì)相應(yīng)地有所下降。這暗示了重要網(wǎng)頁通常距離種子較近,而過度深入抓取到的網(wǎng)頁卻價(jià)值很低。同時(shí),這種策略抓取深度直接影響著抓取命中率以及抓取效率,對(duì)抓取深度是該種策略的關(guān)鍵。相對(duì)于其他兩種策略而言。此種策略很少被使用。

反爬策略

后端的反爬策略一般是通過限制IP訪問頻率以及接口請(qǐng)求頻率來反爬,而前端的反爬策略五花八門,讓人大開眼界:

  • FONT-FACE拼湊式
    代表: 貓眼
    頁面

    字體

    頁面使用了font-face定義了字符集,并通過unicode去映射展示。
    其中woff字體是網(wǎng)頁開放字體格式。
    每次刷新頁面,字符集的url都會(huì)變化,加大爬取成本。
    只能通過圖像識(shí)別(OCR)or爬取字符集去爬取相關(guān)信息。
  • back-ground拼湊式
    代表:美團(tuán)
    頁面

    背景圖

    數(shù)字其實(shí)是圖片,根據(jù)不同的background偏移,顯示不同字符。類似精靈圖。
    不同頁面,圖片的字符及順序都不同,增大了爬蟲難度,增加安全性。
  • 字符干擾式
    代表:微信公眾號(hào)
    頁面

    下劃線部分為干擾文字,方框里為真實(shí)文字。
    通過設(shè)置opacity: 0或者display: none的方式將干擾文字隱藏,起到反爬作用。
  • 偽元素隱藏式
    代表: 汽車之家
    頁面

    把關(guān)鍵的廠商信息,做到了偽元素的content里。
    爬蟲必須要解析css,拿到偽元素的content,提升爬蟲難度。
  • 元素定位覆蓋式
    代表: 去哪兒
    頁面

    對(duì)于4位數(shù)字的機(jī)票價(jià)格,先用4個(gè)i標(biāo)簽渲染,再用兩個(gè)b標(biāo)簽通過絕對(duì)定位覆蓋故意展示錯(cuò)誤的i標(biāo)簽,最后在視覺上形成正確的價(jià)格。
    爬蟲不僅要會(huì)解析css,還要會(huì)做數(shù)學(xué)題。

Coding

使用工具:

  • Node.js —— 搭建后臺(tái)服務(wù)器
  • Express —— 實(shí)現(xiàn)node.js的http封裝及使用
  • Superagent —— 基于node的客戶端請(qǐng)求代理模塊
  • Cheerio —— 基于node的網(wǎng)頁DOM元素操作模塊
  • Nightmare —— 瀏覽器模擬自動(dòng)化庫
  • Ejs —— ssr服務(wù)端渲染ejs模板
  • Echarts —— 基于canvas的可視化圖表模塊

具體實(shí)現(xiàn)步驟
1、Express啟動(dòng)http服務(wù),初始化ejs
2、分析目標(biāo)頁面DOM結(jié)構(gòu),找到目標(biāo)元素,使用工具請(qǐng)求目標(biāo)頁面并獲取數(shù)據(jù)
3、將數(shù)據(jù)注入ejs模板,并形成可視化圖表
4、使用自動(dòng)化工具模擬瀏覽器與用戶行為進(jìn)行測(cè)試

分析DOM結(jié)構(gòu)說明:

目標(biāo)頁面

這個(gè)頁面就是所謂的種子URL,我想要每個(gè)城區(qū)的數(shù)據(jù),就需要進(jìn)入到每個(gè)區(qū)域去獲取數(shù)據(jù),也就是URL隊(duì)列,那么就需要獲取每個(gè)區(qū)域的DOM元素里的URL:

$('.filter .filter__wrapper ul[data-target=area] li>a').each((index, ele) => {
...
})

核心代碼:

// 核心js
const superagent = require('superagent')
const express = require('express')
var router = express.Router()
require('node-jsx').install()
const app = express()
const url = require('url')
const cheerio = require('cheerio')
const fs = require('fs')
const Nightmare = require('nightmare')         // 自動(dòng)化測(cè)試包,處理動(dòng)態(tài)頁面
const nightmare = Nightmare({ show: true })    // show:true  顯示內(nèi)置模擬瀏覽器

//服務(wù)端渲染ejs模板
var ejs = require('ejs')
app.engine('.html',ejs.__express)
app.set('view engine','ejs')
let data = []   // 存放房源具體數(shù)據(jù)
let count = []  // 存放各區(qū)域房源數(shù)量
let allUrl = [] // 存放待抓取url隊(duì)列
//目標(biāo)網(wǎng)站 
let lianjiaUrl = 'https://bj.lianjia.com/'  // url前綴
let zufangUrl = 'https://bj.lianjia.com/zufang/'  // 種子url1
let haidianUrl = 'https://bj.lianjia.com/zufang/haidian/rt200600000001/'    // 種子url2
//分頁規(guī)律 https://bj.lianjia.com/zufang/pg2/#contentList
// #content .content__list--item--main .content__list--item--title a .text()
// href地址
let server = app.listen(3001, function () {
    let host = server.address().address
    let port = server.address().port
    console.log('Your App is running at http://%s:%s', host, port)
  })


// 獲取各區(qū)域房屋套數(shù)
superagent.get(zufangUrl).end((err, res) => {
    if (err) throw err
    let $ = cheerio.load(res.text)
    $('.filter .filter__wrapper ul[data-target=area] li>a').each((index, ele) => {
        let $ele = $(ele)
        let href = url.resolve(lianjiaUrl, $ele.attr('href'))
        superagent.get(href).end((err, res) => {
            if (err) throw err
            let $ = cheerio.load(res.text)
            let houseData = {
                'name': $('.filter .filter__wrapper ul:nth-child(2) li.strong>a').text(),
                'value': $('.content .content__article .content__title .content__title--hl').text()
            }
            count.push(houseData)
        })
    })
})

// 獲取海淀首頁所有房源鏈接元素
superagent.get(haidianUrl).end((err,res)=>{
    if(err) return console.log(err)
    let $ = cheerio.load(res.text)
    $('#content .content__list--item .content__list--item--main>p:first-child>a:first-child').each((index, ele)=>{
        let $ele = $(ele)
        // 拼接單獨(dú)房源url
        let href = url.resolve(lianjiaUrl, $ele.attr('href'))
        allUrl.push(href)
        
        superagent.get(href).end((err, res)=>{
            if(err){
                return console.log(err)
            }
            let $ = cheerio.load(res.text)
            //標(biāo)題  .content p.content__title text()
            //租金 #aside .content__aside--title span內(nèi)的文字
            //格局 .content__aside__list .content__article__table span:nth-child(2) i.typ旁邊的元素
            //平方數(shù) .content__aside__list .content__article__table span:nth-child(2) i.area 旁邊的元素
            // orient旁邊的元素是房間的朝向
            //房源上架時(shí)間 content__subtitle 房源上架時(shí)間 截取10位
            let title = $('div.content .content__title:first-child').text()
            let money = $('#aside .content__aside--title>span:first-child').text()
            let houseType = $('#aside .content__aside__list .content__article__table>span').eq(1).last().html()
            let area = $('#aside .content__aside__list .content__article__table>span').eq(2).last().html()
            
            houseType = houseType.substr(houseType.indexOf('</i>') + 4)
            area = area.substr(area.indexOf('</i>')+4)
            let code = $('#aside .content__aside__list .content__aside__list--bottom:first-child').attr('housecode')
            let upTime = $('div.content .content__subtitle').html()
            upTime = upTime.substr(upTime.indexOf('<i class="hide">')+ 16, upTime.indexOf('<i class="house_code">') - 28)
            upTime = upTime.substr(upTime.indexOf('</i>') + 4)
           // console.log(unescape(upTime.replace(/&#x/g,'%u').replace(/;/g,'')))
            
            let houseData = {
                'title':title,
                'houseCode': code,
                'money':money,
                'href': href,
                'houseType':unescape(houseType.replace(/&#x/g,'%u').replace(/;/g,'')),
                'area': unescape(area.replace(/&#x/g,'%u').replace(/;/g,'')),
                'upTime':unescape(upTime.replace(/&#x/g,'%u').replace(/;/g,'')),
            }
            fs.appendFile('data/result1.json', `${JSON.stringify(houseData)},` ,'utf-8', function (err) {
                if(err) throw new Error("appendFile failed...")
                //console.log("數(shù)據(jù)寫入success...")
            })
            
           // console.log(houseData)
            data.push(houseData)
        })
    })
   
})
app.set('views', './views')
// app.set('view engine', 'pug')
app.get('/',(req, res)=>{
    // res.send('Hello World!')
    res.render('index', { name: '鏈家爬蟲數(shù)據(jù)可視化', data: data})
})

app.post('/fetch',function(req,res){
    res.json({data: data, count: count})
})

app.get('/show',(req, res) =>{
    res.send({
        data: data
    })
})

// 核心ejs模板
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title><%= name %></title>
</head>
<style>
</style>

<body>
    <h1><%= name %></h1>
    <div>
        <div id="main" style="width: 600px;height:400px;">123</div>
        <div id="submain" style="width: 600px;height:400px;">123</div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/4.2.1/echarts-en.common.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script type="text/javascript">
    
        $.ajax({
            type: 'POST',
            url: '/fetch'
        }).done(function (results) {
            console.log('results', results); //=>params
            const areaRange = ['西城', '東城', '海淀', '朝陽', '昌平', '通州', '大興']
            // 計(jì)算一、二、三居均價(jià)及面積
            let oneRoomPrice = [];
            let oneRoomArea = [];
            let twoRoomPrice = [];
            let twoRoomArea = [];
            results.data.forEach(v => {
                if (v.title.includes('1室')) {
                    oneRoomPrice.push(parseInt(v.money))
                    oneRoomArea.push(parseInt(v.area))
                } else if (v.title.includes('2室')) {
                    twoRoomPrice.push(parseInt(v.money))
                    twoRoomArea.push(parseInt(v.area))
                }
            })

            function average (data) {
                return parseInt(data.reduce((a, b) => a + b) / data.length)
            }

            // 基于準(zhǔn)備好的dom,初始化echarts實(shí)例
            var myChart = echarts.init(document.getElementById('main'));
            var pieChart = echarts.init(document.getElementById('submain'));

            // 指定圖表的配置項(xiàng)和數(shù)據(jù)
            var option = {
                color: ['#4cabce', '#e5323e'],
                title: {
                    text: '海淀區(qū)房屋租賃情況統(tǒng)計(jì)'
                },
                tooltip: {
                    trigger: 'axis',
                    axisPointer: {
                        type: 'shadow'
                    }
                },
                legend: {
                    data: ['均價(jià)', '面積']
                },
                xAxis: {
                    axisTick: {show: true},
                    data: ['一居', '兩居']
                },
                yAxis: [{type: 'value'}],
                series: [{
                    name: '均價(jià)',
                    type: 'bar',
                    data: [average(oneRoomPrice), average(twoRoomPrice)]
                }, {
                    name: '面積',
                    type: 'bar',
                    data: [average(oneRoomArea) * 100, average(twoRoomArea) * 100]
                }]
            };

            var pieOption = {
                    backgroundColor: '#2c343c',

                    title: {
                        text: '北京各區(qū)域房源數(shù)量統(tǒng)計(jì)',
                        left: 'center',
                        top: 20,
                        textStyle: {
                            color: '#ccc'
                        }
                    },

                    tooltip : {
                        trigger: 'item',
                        formatter: "{a} <br/> : {c} (ifhziew%)"
                    },

                    visualMap: {
                        show: false,
                        min: 80,
                        max: 600,
                        inRange: {
                            colorLightness: [0, 1]
                        }
                    },
                    series : [
                        {
                            name:'訪問來源',
                            type:'pie',
                            radius : '55%',
                            center: ['50%', '50%'],
                            data:results.count.filter(v => areaRange.includes(v.name)).sort(function (a, b) { return a.value - b.value; }),
                            roseType: 'radius',
                            label: {
                                normal: {
                                    textStyle: {
                                        color: 'rgba(255, 255, 255, 0.3)'
                                    }
                                }
                            },
                            labelLine: {
                                normal: {
                                    lineStyle: {
                                        color: 'rgba(255, 255, 255, 0.3)'
                                    },
                                    smooth: 0.2,
                                    length: 10,
                                    length2: 20
                                }
                            },
                            itemStyle: {
                                normal: {
                                    color: '#c23531',
                                    shadowBlur: 200,
                                    shadowColor: 'rgba(0, 0, 0, 0.5)'
                                }
                            },

                            animationType: 'scale',
                            animationEasing: 'elasticOut',
                            animationDelay: function (idx) {
                                return Math.random() * 200;
                            }
                        }
                    ]
            };

            // 使用剛指定的配置項(xiàng)和數(shù)據(jù)顯示圖表。
            myChart.setOption(option);
            pieChart.setOption(pieOption);
        })
    </script>
</body>

</html>

拿到的數(shù)據(jù)是這樣的:


數(shù)據(jù)

形成可視化:


最終成果

瀏覽器自動(dòng)化測(cè)試神器:Nightmare
特異功能:

  • 內(nèi)置模擬瀏覽器,掌控一切
  • 等待DOM元素出現(xiàn),應(yīng)對(duì)異步加載
  • 模擬用戶行為,自動(dòng)輸入文本
  • 模擬用戶行為,自動(dòng)點(diǎn)擊元素
  • 在客戶端注入JS腳本并執(zhí)行
    。。。
// 通過瀏覽器自動(dòng)化庫獲取數(shù)據(jù)
nightmare
.goto(zufangUrl)
.wait('.filter .filter__wrapper ul[data-target=area] li>a')
.type('.search__wrap input.search__input', '海淀第一海景房')
// .click('.filter .filter__wrapper ul[data-target=area] li:nth-child(2)>a')
.evaluate(() => document.querySelector(".wrapper").innerHTML)
.then(htmlStr => {
    let $ = cheerio.load(htmlStr)
    $('.filter .filter__wrapper ul[data-target=area] li>a').each((index, ele) => {
        let $ele = $(ele)
        let href = url.resolve(lianjiaUrl, $ele.attr('href'))
        superagent.get(href).end((err, res) => {
            if (err) throw err
            let $ = cheerio.load(res.text)
            let houseData = {
                'name': $('.filter .filter__wrapper ul:nth-child(2) li.strong>a').text(),
                'value': $('.content .content__article .content__title .content__title--hl').text()
            }
            count.push(houseData)
        })
    })
})
.catch(error => {
  console.log(`抓取失敗 - ${error}`)
})

它可以打開一個(gè)無頭的模擬瀏覽器窗口,去進(jìn)行各種常規(guī)瀏覽器不能進(jìn)行的操作,比如模擬用戶輸入內(nèi)容:


模擬瀏覽器

總結(jié)

  • 概念:抓取萬維網(wǎng)數(shù)據(jù)的執(zhí)行腳本
  • 工作原理:從種子url進(jìn)入,展開工作
  • 爬行策略:廣度優(yōu)先、最佳優(yōu)先、深度優(yōu)先
  • 反爬策略:增大爬行成本,但無法完全防止
  • Coding:使用各種工具對(duì)目標(biāo)網(wǎng)頁進(jìn)行爬取
  • 自動(dòng)化測(cè)試工具:內(nèi)置瀏覽器,模擬用戶行為

關(guān)于爬蟲,還有很多深入的有趣的東西可以研究,比如身份驗(yàn)證以及其他反爬攻防戰(zhàn),歡迎各位共同探討!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,481評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,241評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,697評(píng)論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,182評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,406評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,933評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,772評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,973評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評(píng)論 1 285
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,644評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,953評(píng)論 2 373

推薦閱讀更多精彩內(nèi)容

  • 網(wǎng)絡(luò)數(shù)據(jù)采集是指通過網(wǎng)絡(luò)爬蟲或網(wǎng)站公開 API 等方式從網(wǎng)站上獲取數(shù)據(jù)信息。該方法可以將非結(jié)構(gòu)化數(shù)據(jù)從網(wǎng)頁中抽取出...
    yoku醬閱讀 1,201評(píng)論 0 2
  • 1.愛的動(dòng)作:經(jīng)常跟孩子作肢體上的溫柔接觸,如輕拍他的肩膀,走路時(shí)牽著他的手或攬著他的肩,替他整理衣領(lǐng)頭發(fā),跟孩子...
    般若1987閱讀 349評(píng)論 2 7
  • 21009-尹思函 孩子總是在不經(jīng)意間就長大了,有了自己想法和小心思,也多了很多的疑問,也會(huì)犯一些錯(cuò)誤。我們應(yīng)該做...
    尹思函閱讀 252評(píng)論 0 0
  • 解決方法很簡單 第一步:先用cocopods將snapkit第三方庫導(dǎo)入工程,打開工程后會(huì)彈出Swift版本較早,...
    淺淺_e90e閱讀 370評(píng)論 0 0
  • 今天第三節(jié)在我們一年級(jí)聽第一課《吃水不忘挖井人》我先是帶著孩子們把詞語復(fù)習(xí)了一下,然后進(jìn)入課文學(xué)習(xí),我?guī)ьI(lǐng)孩子們一...
    撞衫了閱讀 292評(píng)論 0 0