用前端的方式打开豆瓣租房小组

标题略显浮夸...大家不要介意@_@

最近要去上海打工,网上查了一下,很多人说豆瓣租房小组租房子挺靠谱的,于是就百度了一下,点进去的界面是这样的...


用前端的方式打开豆瓣租房小组_第1张图片
豆瓣租房小组首页

用前端的方式打开豆瓣租房小组_第2张图片
帖子详情页

看到首页的时候就感觉有点头大,有种零几年逛贴吧论坛的感觉,就直接罗列标题,没有缩略图,你要点进去才能查看具体的房源信息,房子图片,有点麻烦。

为了方便浏览,我决定利用所学知识对该界面进行优化,把纯文字的界面转化成这种“标题+图片的形式”,浏览信息更直观方便一些,下面先上效果图,图中没有图片的地方是因为原贴就没有图片。


用前端的方式打开豆瓣租房小组_第3张图片
豆瓣租房优化.png

1. 思路

先解释一下,我说的优化的意思不是写个浏览器脚本或插件,然后打开这个网页会自动转化,这种技术对于我来说太难了......

我的想法是,先爬取这个网页的关键数据,保存成json文件,然后再写一个静态网页展示这些数据,当然一些链接也会爬取下来,所以最后即使我做的是静态网页,但点击相应的帖子,我也能跳转到原贴的详情页,营造出一种真实网站的感觉

2. 涉及的技术

  • Python:要爬取网页信息,这里我选择用Python,同时使用到了requests库和lxml库。
  • 前端技术:HTMLCSSJavaScript素质三连,为了便于展示数据我用到了Vue2.0,懒得写分页,所以也用到了Bootstrap的分页组件。

3. 代码实现

3.1 爬取网页信息

import json
import requests
from lxml import html


class spider:
    def __init__(self):
        self.page = 0
        self.url = 'https://www.douban.com/group/search?start={}&cat=1013&group=146409&sort=time&q=%E9%97%B5%E8%A1%8C'.format(self.page)
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        }

    def get_html(self, url):
        response = requests.get(url, headers=self.headers).text
        html_tree = html.fromstring(response)
        return html_tree

    def get_img(self, href):
        html_data = self.get_html(href)
        img = html_data.xpath('//*[@id="link-report"]//*[@class="image-wrapper"]/img/@src')[:4]
        return img

    def save_files(self, filename, array):
        try:
            with open(filename, 'w', encoding='utf-8') as json_data:
                json.dump(array, json_data, ensure_ascii=False)
                print('**********写入成功**********')
        except EnvironmentError:
            print('写入失败')

    def get_data(self):
        json_data = []
        data = {}
        html_data = self.get_html(self.url)
        title_list = html_data.xpath('//*[@class="olt"]/tbody/tr/td[1]/a/@title')
        href_list = html_data.xpath('//*[@class="olt"]/tbody/tr/td[1]/a/@href')
        time_list = html_data.xpath('//*[@class="olt"]/tbody/tr/td[2]/@title')
        for title, href, time in zip(title_list, href_list, time_list):
            img = self.get_img(href)
            data['title'] = title
            data['href'] = href
            data['img'] = img
            data['time'] = time
            json_data.append(data)
            print('已获取: ' + title)
            data = {}

        return json_data

    def next_page(self):
        self.page += 50
        self.url = 'https://www.douban.com/group/search?start={}&cat=1013&group=146409&sort=time&q=%E9%97%B5%E8%A1%8C'.format(self.page)

    def run(self, page_num):
        json_data = []
        flag = page_num
        while page_num > 0:
            json_data += self.get_data()
            print('已获取第', flag - page_num + 1, '页')
            self.next_page()
            page_num -= 1

        self.save_files('./data.json', json_data)


s = spider()
s.run(5)  # 爬取5页

纯粹的笨方法爬取,没有多线程也没有异步,下面解释一下代码:

  • get_html(url):获取原始网页,整理成树结构,方便xpath语法解析。
  • get_img(href):获取帖子中的图片地址。
  • get_data():获取title文本,链接,发布时间等信息,return返回json数据。
  • next_page(url):爬取下一页,观察url信息,发现每下一页,url中的某个参数递增50,所以直接+50。
  • save_files(filename, array):把json数据保存成data.json文件。
  • run(page_num):设定爬取的页数,然后执行。

运行后爬取到data.json文件:

用前端的方式打开豆瓣租房小组_第4张图片
data.json文件.png

3.2 用静态网页展示

  • html代码



    
    

    
    

    
    

    豆瓣租房小组


    
  • CSS代码
body {
    border: 1px solid #ddd;
    margin: auto;
    width: 1080px;
    box-shadow: 2px 2px 10px 2px #ccc;
}

#header {
    margin-bottom: 5em;
    text-align: center;
}

#fileImport {
    font-size: 18px;
}

#content ul {
    margin: 0;
    padding: 0;
}

#content ul li {
    list-style: none;
    margin: 1em 0.5em;
    padding: 1em 0;
    border-top: 1px solid #999;
}

.info-list .title-list {
    display: flex;
}

.info-list .title-list span {
  display: inline-block;
  width: 3em;
  font-style: italic;
  font-size: 1.5em;
  color: #eb5f00;
  text-align: center;
}

.info-list .title-list a {
    text-decoration: none;
    font-size: 1.5em;
    color: black;
}
.info-list .title-list a:hover {
    color: #e79600;
}

.info-list .img-box {
    display: flex;
    margin-left: 4em; 
}

.info-list .img-box img {
    margin: 0.5em;
    width: 200px;
    height: 200px;
}

.info-list .release-time {
    margin-left: 4em;
    padding-top: 1em;
    font-size: 16px;
    color: #999;
}
  • js代码
const index = new Vue({
    el: '#content',
    data: {
        json_data: [], // 租房信息数据
        num: 0, //多少条数据
        pageNum: [], //总页数转化成列表
        pageSize: 15, //每一页的数量
        totalPage: 1, //总页数
        curPage: 1, //当前页数
        showPageList: 0, //当前显示的页面
    },

    // 监听器
    watch: {
        json_data(newData){
            this.pageNum = []; // 若数据更新,页码先清零
            this.num = newData.length;
            this.totalPage = Math.ceil(this.num / this.pageSize);
            this.totalPage = this.totalPage == 0 ? 1 : this.totalPage;
            this.change_list();
            this.getShowPageList(newData, this.curPage);
        },
        curPage(newPage){
            this.getShowPageList(this.json_data, newPage);
        }
    },

    // 事件处理方法
    methods: {   
        // 点击触发选择文件按钮
        files_click: function(){
            $("#files").click();
        },

        // 读取json文件 
        get_json_data: function(e){
            var self = this;  // 保存外部作用域
            var selectedFile = e.target.files[0];
            var reader = new FileReader();
            reader.readAsText(selectedFile);
            reader.onload = function () {
                self.json_data = JSON.parse(this.result); // 读取的是字符串,转换数组
            }  
        },

        // 页数转换成数组
        change_list: function(){
            for (let i = 1; i <= this.totalPage; i++) {
                this.pageNum.push(i)
            }
        },

        // 获取当前页应展示的数据
        getShowPageList: function(data, index){         
            let begin = (index - 1) * this.pageSize;
            let end = index * this.pageSize;
            this.showPageList = data.slice(begin, end);
        },

        // 上一页
        prevPage: function(e){
            if(this.curPage != 1){
                this.curPage --;
            }
        },

        // 下一页
        nextPage: function(e){
            if(this.curPage != this.totalPage){
                this.curPage ++;
            }
        },

        // 点击页面跳转
        link_curPage: function(e){
            console.log(e.target.text);
            let num = parseInt(e.target.text);
            this.curPage = num; 
        }
    }
})

最后我是用js的FileReader接口读取的json文件,查资料的时候有人说可以用Ajax读取,但我试了一下发现会产生跨域。手动导入文件显得太笨了......没办法,能力有限,后续有空再尝试优化一下这个问题。

代码就不解释了,思路就是读取json文件,本质上这些json数据都是数组,使用Vue可以轻松的展示这些数据

你可能感兴趣的:(用前端的方式打开豆瓣租房小组)