教隔壁小姐姐搭建Python爬蟲比價(jià)網(wǎng)站

隔壁的小姐姐讓我和她七夕呆一天,我想一天那么長,光聊天肯定很無聊,那么做點(diǎn)什么好呢?

想到這幾天正好在學(xué)Python爬蟲,于是我精心準(zhǔn)備了搭建Python爬蟲網(wǎng)站的教程,教小姐姐用Python,這樣肯定不會(huì)無聊了O(∩_∩)O哈哈~

最終效果展示

01 基礎(chǔ)知識(shí)

為了讓小姐姐能聽懂,我提前跟她說了要預(yù)習(xí)的知識(shí)。

微信圖片

當(dāng)然,小姐姐也是有一定python基礎(chǔ)的,有了上面的準(zhǔn)備,相信我們一定能做一個(gè)深入的學(xué)習(xí)討論。

02 實(shí)現(xiàn)思路

這個(gè)項(xiàng)目主要由三個(gè)部分組成

  • 爬蟲:爬取京東、1號店和淘寶的商品信息實(shí)現(xiàn)價(jià)格比較
  • Flask:運(yùn)用Flask構(gòu)建Web應(yīng)用,顯示爬蟲結(jié)果
  • pythonanywhere:通過pythonanywhere將Web應(yīng)用部署到云
實(shí)現(xiàn)思路

03 爬蟲

第一步是用python爬蟲腳本抓取網(wǎng)頁上的商品信息,這里我們主要對京東、1號店和淘寶的商品信息進(jìn)行爬取。不同的網(wǎng)頁需要進(jìn)行不同的分析,但方法都是大同小異的。我們先以1號店為例看看如何編寫爬蟲代碼。

一、爬取1號店的商品數(shù)據(jù)

開始之前我們需要引入下面的python庫:

import requests
from lxml import html
import urllib.parse

接下來,我們定義函數(shù)crawler:

def crawler(word, products_list=[]):

這里的word就是我們需要搜索商品名稱,而products_list用來保存我們的爬取結(jié)果。

word = urllib.parse.quote(word)

當(dāng)我們查詢的商品名稱含有中文時(shí),是要對其進(jìn)行編碼處理的,urllib.parse.quote()函數(shù)可以幫助實(shí)現(xiàn)這一點(diǎn)。
當(dāng)我們在1號店搜索商品名稱時(shí),其實(shí)是發(fā)起了一個(gè)url請求,這個(gè)url中包含了我們要查詢的信息。因此我們需要將word參數(shù)加入到url中。

url = 'https://search.yhd.com/c0-0/k{0}'.format(word)

接下來的三步順其自然,獲取html源碼,將html源碼轉(zhuǎn)換為xpath對象,然后在html樹狀結(jié)構(gòu)中尋找包含商品信息的節(jié)點(diǎn)。

# 獲取html源碼
html_doc = requests.get(url).text

# xpath對象
selector = html.fromstring(html_doc)

# 商品列表
ul_list = selector.xpath('//div[@id="itemSearchList"]/div')

得到了當(dāng)前頁面的商品列表之后,我們需要對其進(jìn)行遍歷獲取其中每個(gè)商品的名稱、價(jià)格、購買鏈接和店鋪信息。

    for li in ul_list:
        # 名稱
        title = li.xpath('div//p[@class="proName clearfix"]/a/@title')
        # 鏈接
        link = li.xpath('div//p[@class="proName clearfix"]/a/@href')
        # 價(jià)格
        price = li.xpath('div//p[@class="proPrice"]/em/@yhdprice')
        # 店鋪
        store = li.xpath('div//p[@class="storeName limit_width"]/a/@title')

最后將我們爬取到的結(jié)果,存入products_list中為最后的價(jià)格比較做準(zhǔn)備。

products_list.append({
                'title': title[0],
                'price': price[0],
                'link': 'https:' + link[0],
                'store': store[0],
                'referer': '1號店'
            })

二、爬取京東的商品數(shù)據(jù)

京東商品信息的爬取與1號店十分相似,需要注意的是京東網(wǎng)頁獲取html信息后,需要進(jìn)行utf-8編碼才能正常顯示頁面。
直接上源碼:

import requests
from lxml import html


def crawler(word, products_list=[]):
    """ 爬取京東的商品數(shù)據(jù) """
    url = 'https://search.jd.com/Search?keyword={0}&enc=utf-8'.format(word)

    # 獲取HTML文檔
    respons = requests.get(url)
    respons.encoding = 'utf-8'
    html_doc = respons.text

    # 獲取xpath對象
    selector = html.fromstring(html_doc)

    # 找到列表的集合
    ul_list = selector.xpath('//div[@id="J_goodsList"]/ul/li')

    # 解析對應(yīng)的標(biāo)題,價(jià)格,鏈接,店鋪
    for li in ul_list:

        # 標(biāo)題
        title = li.xpath('div/div[@class="p-name p-name-type-2"]/a/em/text() | '
                         'div/div[@class="p-name"]/a/@title')

        # 購買鏈接
        link = li.xpath('div/div[@class="p-name p-name-type-2"]/a/@href | '
                        'div/div[@class="p-name"]/a/@href')

        # 價(jià)格
        price = li.xpath('div/div[@class="p-price"]/strong/i/text() | '
                         'div/div[@class="p-price"]/strong/i/text()')

        # 店鋪
        store = li.xpath('div/div[@class="p-shop"]//a/text() | '
                         'div//a[@class="curr-shop"]/@title')

        products_list.append({
                'title': title[0],
                'price': price[0],
                'link': 'https:' + link[0],
                'store': store[0],
                'referer': '京東'
            })

if __name__ == '__main__':
    a = []
    crawler('爬蟲', a)

三、爬取淘寶商品信息

淘寶商品信息的爬取就和前面兩者有很大不同了,這里我們無法用xpath尋找包含商品信息的節(jié)點(diǎn),查看網(wǎng)頁源代碼會(huì)發(fā)現(xiàn)根本就沒有包含商品信息的html標(biāo)簽。這主要是因?yàn)樘詫毷峭ㄟ^傳遞json數(shù)據(jù)來更新頁面數(shù)據(jù)的。

因此這里的url不是一個(gè)網(wǎng)址,而是一個(gè)api接口:

url = 'https://s.taobao.com/api?ajax=true&m=customized&sourceId=tb.index&q={0}'.format(word)

當(dāng)我們得到了淘寶傳遞的json數(shù)據(jù)后,后面的過程就很簡單了,在json中尋找目標(biāo)信息要比在html樹狀結(jié)構(gòu)中尋找方便多了。

源碼如下:

import requests
import urllib.parse


def crawler(word, products_list=[]):
    """ 爬取淘寶網(wǎng)的商品數(shù)據(jù) """
    word = urllib.parse.quote(word)

    url = 'https://s.taobao.com/api?ajax=true&m=customized&sourceId=tb.index&q={0}'.format(word)
    rest = requests.get(url).json()
    pr_list = rest["API.CustomizedApi"]["itemlist"]["auctions"]

    for bk in pr_list:
        title = bk['raw_title']
        price = bk['view_price']
        link = bk['detail_url']
        store = bk['nick']
      
        products_list.append({
            'title': title,
            'price': price,
            'link': 'https:' + link,
            'store': store,
            'referer': '淘寶'
        })


if __name__ == '__main__':
    a = []
    crawler('python', a)

四、綜合比價(jià)

綜合比價(jià)需要我們導(dǎo)入前面三個(gè)爬蟲腳本,并按價(jià)格由低到高的排序得到最終結(jié)果。

from crawler_jd import  crawler as jd
from crawler_yhd import crawler as yhd
from crawler_taobao import crawler as taobao


def main(word):
    """ 比價(jià)工具整合 """
    products_list = []

    # 京東數(shù)據(jù)
    print('京東網(wǎng)數(shù)據(jù)爬取完成')
    jd(word, products_list)

    # 1號店數(shù)據(jù)
    print('1號店數(shù)據(jù)爬取完成')
    yhd(word, products_list)

    # 淘寶數(shù)據(jù)
    print('淘寶網(wǎng)數(shù)據(jù)爬取完成')
    taobao(word, products_list)

    print('-------------------------開始排序---------------------------------')

    # 排序書的數(shù)據(jù)
    products_list = sorted(products_list, key=lambda item: float(item['price']), reverse=False)
    for products in products_list:
        print(products)
    return products_list


if __name__ == '__main__':
    word = input('請輸入商品名稱:')
    main(word)

04 Flask

Flask提供了一組模塊,可以幫助我們構(gòu)建服務(wù)器端Web應(yīng)用,由于我們的爬蟲網(wǎng)站功能簡單,所以Flask這個(gè)輕量級的框架就夠了。

from flask import Flask, render_template, request
from crawler_product import main

app = Flask(__name__)


@app.route('/')
def entry_page() -> 'html':
    return render_template('entry.html',
                           the_title='Welcome to PriceCompare!')


@app.route('/compare', methods=['POST'])
def search_products() -> str:
    word = request.form['word']
    title = '比價(jià)結(jié)果'
    titles = ('商品', '價(jià)格', '鏈接', '店鋪', '來源')
    results = main(word)
    return render_template('results.html',
                           the_word=word,
                           the_title=title,
                           the_row_titles=titles,
                           the_data=results,)


app.run()

entry_page明確了Flask web應(yīng)用的初始頁面是entry.html,并向其中傳入了我們想要顯示的信息。
entry.html源碼:

{% extends 'base.html' %}

{% block body %}

<h2>{{ the_title }}</h2>

<form method='POST' action='/compare'>
<table>
<p>請輸入想要比價(jià)的商品:</p>
<tr><td>商品:</td><td><input name='word' type='TEXT' width='60'></td></tr>
</table>
<p>準(zhǔn)備好了,點(diǎn)擊這里:</p>
<p><input value='Do it!' type='SUBMIT'></p>
</form>

{% endblock %}

search_products接收了entry.html傳入的word參數(shù),并交由crawler_product進(jìn)行爬蟲,最后向results.html傳遞爬蟲結(jié)果。
results.html源碼:

{% extends 'base.html' %}

{% block body %}

<h2>{{ the_title }}</h2>

<p>你提交的商品名稱:</p>
<table>
<tr><td>關(guān)鍵字:</td><td>{{ the_word }}</td></tr>
</table>

<p>下面是 "{{ the_word }}" 的搜索比價(jià)結(jié)果:</p>
<table>
    <tr>
        {% for row_title in the_row_titles %}
            <th>{{row_title}}</th>
        {% endfor %}
    </tr>
    {% for products in the_data %}
    <tr>
        <td>{{products['title']}}</td>
        <td>{{products['price']}}</td>
        <td><a href={{products['link']}}>{{products['link']}}</a></td>
        <td>{{products['store']}}</td>
        <td>{{products['referer']}}</td>
    </tr>
    {% endfor %}
</table>

{% endblock %}

到這里我們所有的代碼都已經(jīng)準(zhǔn)備完畢,我們可以看看整個(gè)項(xiàng)目的源碼結(jié)構(gòu):

項(xiàng)目結(jié)構(gòu)

crawler_jd.py、crawler_yhd.pycrawler_taobao.py分別為三個(gè)網(wǎng)頁的爬蟲腳本,通過crawler_product.py進(jìn)行綜合比較。

Flask_PriceCompaer.py是Flask Web應(yīng)用核心代碼,創(chuàng)建Flask對象并傳遞數(shù)據(jù)。

templates文件夾下的base.html是前端頁面的基模板,entry.html繼承了基模板負(fù)責(zé)網(wǎng)站進(jìn)入頁面的顯示,results.htmlentry.html類似,負(fù)責(zé)網(wǎng)站結(jié)果頁面的顯示。
static文件夾下的hf.css就是普通的css文件,負(fù)責(zé)頁面的美化。

我們可以運(yùn)行Flas_PriceCompaer.py來看看網(wǎng)站的整體效果。

頁面入口:

entry

查詢結(jié)果:

results

源碼下載

05 pythonanywhere

最后,只要10分鐘就可以把我們的Web應(yīng)用部署到云上,通過公網(wǎng)快捷地訪問Python爬蟲比價(jià)網(wǎng)站。

一、注冊Pythonanywhere

將網(wǎng)站源代碼打包壓縮,訪問pythonanywhere.com,并進(jìn)行注冊。

二、將文件上傳到云

文件上傳

三、解壓縮和安裝代碼

文件上傳后,點(diǎn)擊Open Bash console here,Pythonanywhere會(huì)彈出Linux控制臺(tái),我們執(zhí)行兩條命令:
unzip PriceCompaer.zip
mv PriceCompaer/* mysite/
將web應(yīng)用的代碼安裝到mysite文件夾。

四、創(chuàng)建一個(gè)初始Web應(yīng)用

創(chuàng)建Web應(yīng)用

點(diǎn)擊Add a new web app后,一路next,并選擇web framework為Flask以及相應(yīng)python版本。

五、配置Web應(yīng)用

接下來我們點(diǎn)擊下圖提示的位置:

5.PNG

修改from flask_app import app as application,將flask_app修改為我們自己的Flask Web應(yīng)用代碼,如Flask_PriceCompaer。同時(shí),我們也要查看Flask_PriceCompaer.py 文件,確保最后沒有app.run()

六、運(yùn)行

配置完成后,就可以點(diǎn)擊那個(gè)綠色的Reload按鈕開始運(yùn)行了。

PS:要提醒的是,pythonanywhere免費(fèi)版只能訪問特定的網(wǎng)站,所以爬蟲程序無法運(yùn)行,想體檢完整結(jié)果請自行升級收費(fèi)版。

06 寫在最后

這篇文章主要是記錄自己的實(shí)現(xiàn)思路以及方法,其中的原理并沒有進(jìn)行詳細(xì)的闡述。雖然主要是因?yàn)槟菢訉懙脑捥哿?,但更重要的是,爬蟲、Flask和pythonanywhere網(wǎng)上都有大量的教程,在大神們的教程里浪費(fèi)時(shí)間才更有意義。

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

相關(guān)閱讀更多精彩內(nèi)容

  • # Python 資源大全中文版 我想很多程序員應(yīng)該記得 GitHub 上有一個(gè) Awesome - XXX 系列...
    aimaile閱讀 26,832評論 6 427
  • # Python 資源大全中文版 我想很多程序員應(yīng)該記得 GitHub 上有一個(gè) Awesome - XXX 系列...
    小邁克閱讀 3,122評論 1 3
  • Python資源大全中文版,包括:Web框架、網(wǎng)絡(luò)爬蟲、模板引擎、數(shù)據(jù)庫、數(shù)據(jù)可視化、圖片處理等,由伯樂在線持續(xù)更...
    dxl1236閱讀 4,834評論 2 33
  • 英文原版:https://github.com/vinta/awesome-python中文版:https://g...
    會(huì)灰的大飛狼閱讀 3,693評論 1 56
  • 我總是懷揣著這樣的認(rèn)知:很多時(shí)候,哭和笑一樣,都只是一瞬悲和喜的心境的釋放。 直到有人一邊笑著看我哭一邊問我:“你...
    窩書閱讀 318評論 1 5

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