溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Python實(shí)現(xiàn)商品價(jià)格監(jiān)控的方法

發(fā)布時(shí)間:2020-08-03 15:10:14 來源:億速云 閱讀:1114 作者:清晨 欄目:編程語言

這篇文章將為大家詳細(xì)講解有關(guān)Python實(shí)現(xiàn)商品價(jià)格監(jiān)控的方法,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

一年一度的“雙十一”又要來了,很多人已經(jīng)開始摩拳擦掌,畢竟幾天之后手還在不在就不好說了。

各種社交軟件也是跟著遭殃,整天就是“來幫我一起蓋樓”,各種字體繞過屏蔽,什么奇葩的腦洞也出來了:

Python實(shí)現(xiàn)商品價(jià)格監(jiān)控的方法

不過也感謝這些電商平臺(tái),讓多年未聯(lián)系的好友、加過但沒有對(duì)話的陌生人都找到了打破尷尬的話題。(讓場(chǎng)面更加尷尬)

月薪上萬的白領(lǐng)們?yōu)榱?塊5毛錢的優(yōu)惠券起早貪黑,也是堪稱人類迷惑行為大賞了……

問題是,你以為自己真的賺到了?

商品“明降暗升”的傳言早有耳聞:很多商品在雙十一之前早早地把價(jià)格調(diào)高,加上優(yōu)惠之后也不過就是跟以前的原價(jià)相當(dāng)。讓不知情的消費(fèi)者在心理上感覺占了便宜。

這個(gè)傳言是不是真的,很好判斷,只要定期去訪問商品頁面,記錄價(jià)格就可以。不過一般人也沒閑工夫這么去做。于是,我們用 Python 做了一個(gè)可以定時(shí)監(jiān)控商品的小工具,可以幫你監(jiān)控想要關(guān)注的商品。

工具完成之后,我們隨機(jī)挑選了幾個(gè)商品作為測(cè)試,結(jié)果就有一個(gè)中招了……(真的是隨便選的):

Python實(shí)現(xiàn)商品價(jià)格監(jiān)控的方法

這款保暖背心產(chǎn)品,之前標(biāo)價(jià) 39.9元,到11月之后卻突然調(diào)價(jià)為 49.9元,并標(biāo)注上了“雙11狂歡價(jià)”,也就是原價(jià)……

Python實(shí)現(xiàn)商品價(jià)格監(jiān)控的方法

Python實(shí)現(xiàn)商品價(jià)格監(jiān)控的方法

商品價(jià)格監(jiān)控

實(shí)現(xiàn)功能

·輸入天貓、蘇寧、京東、拼多多(網(wǎng)頁頁面 http://yangkeduo.com/)任一商品鏈接,不是口令。請(qǐng)復(fù)制選擇好商品配置的頁面鏈接,即返回相應(yīng)商品價(jià)格,并保存到文件。商品頁面若有團(tuán)購(gòu)與單獨(dú)購(gòu)買兩個(gè)價(jià)格,返回團(tuán)購(gòu)價(jià)格。

·使用 Windows 任務(wù)計(jì)劃或 Linux 定時(shí)任務(wù),定時(shí)執(zhí)行程序。獲取不同時(shí)段的商品價(jià)格信息。

·單獨(dú)運(yùn)行畫圖程序,可根據(jù)定時(shí)任務(wù)獲取的數(shù)據(jù),生成商品價(jià)格時(shí)間變化折線圖。

·程序監(jiān)測(cè)的兩件商品截圖如下,具體文件在 pic 文件夾下 bnbx.html、kyy.html,推薦本地查看。

Python實(shí)現(xiàn)商品價(jià)格監(jiān)控的方法

Python實(shí)現(xiàn)商品價(jià)格監(jiān)控的方法

簡(jiǎn)單的商品查看頁面 https://htmlpreview.github.io/?https://raw.githubusercontent.com/spiderbeg/price_monitor/master/search/search.html 。輸入查詢商品關(guān)鍵詞,選擇商城,即可查看相應(yīng)商城商品列表。默認(rèn)為蘇寧。效果圖如下。注意:點(diǎn)擊后請(qǐng)等待一段時(shí)間即可,請(qǐng)勿頻繁刷新。

Python實(shí)現(xiàn)商品價(jià)格監(jiān)控的方法

運(yùn)行環(huán)境

·python3.7

·Windows

·jupyter notebook

運(yùn)行依賴包

·requests

·pyecharts

·beautifulsoup4

項(xiàng)目思路

部分問題回答

項(xiàng)目的大致思路流程:

·第一步:使用商品詳細(xì)頁鏈接獲取商品信息與商品價(jià)格,并保存獲取數(shù)據(jù) 時(shí)間、商品介紹,價(jià)格 到 csv 文件中;

·第二步:使用定時(shí)任務(wù)定時(shí)執(zhí)行第一步完成的程序;

·第三步:讀取前兩步獲取到的時(shí)間、商品介紹、價(jià)格數(shù)據(jù)。使用 pyecharts 繪制繪制商品價(jià)格時(shí)間變化折線圖。

為什么不使用 pc 端來調(diào)試網(wǎng)頁,獲取價(jià)格信息?

因?yàn)樵谖吹卿洜顟B(tài)天貓的詳細(xì)商品頁的信息是虛假的,同時(shí)從移動(dòng)端網(wǎng)頁入手,可以降低調(diào)試難度。

谷歌瀏覽器如何開啟手機(jī)調(diào)試模式?

F12 進(jìn)入開發(fā)者模式,然后鼠標(biāo)點(diǎn)擊一下,具體見下圖,包括后文的查找價(jià)格接口信息。

Python實(shí)現(xiàn)商品價(jià)格監(jiān)控的方法

實(shí)現(xiàn)代碼

test.py

測(cè)試商品鏈接是否能夠成功獲取到商品價(jià)格。

import timing
"""
1、調(diào)用 timing.py 中的 go 方法測(cè)試鏈接的可用性
2、調(diào)用 timing.py 中的 go, get_url() 方法測(cè)試 goods.csv 文件中鏈接的可用性
"""
# 鏈接測(cè)試
# urls = ['https://m.suning.com/product/0000000000/000000011210599174.html?utm_source=baidu&utm_midium=brand-wuxian 
&utm_content=&utm_campaign=title&safp=f73ee1cf.wapindex7.113464229882.4&safc=prd.1.rec_14-40_0_A_ab:A',
# 'https://m.suning.com/product/0070067092/000000000188392234.html?utm_source=baidu&utm_midium=brand-wuxian& 
utm_content=&utm_campaign=title&safp=f73ee1cf.wapindex7.113464229882.60&safc=prd.1.rec_5-5_1018C,1014C$
c3ae37eafeb814a098d120647449da6f_H_ab:A',
# 'https://m.suning.com/product/0000000000/000000000107426461.html?src=snsxpd_none_recssxcnxhq_1-3_p_0000000000 
_000000000107426461_rec_21-65_3_A&safp=f73ee1cf.71jyzx.112079032536.4&safc=prd.1.rec_21-65_3_A',
# 'https://m.suning.com/product/0000000000/10606656136.html?safp=f73ee1cf.phone2019.121927933306.2&safc=prd.0.0']
# 輸入文本的鏈接可用性測(cè)試
if __name__ == '__main__':
    urls = timing.get_url()
    for url in urls:
        try:
            timing.go(url) # 獲取返回信息 
        except BaseException as e:
            print(url,'\n',e)

timing.py

進(jìn)行定時(shí)抓取任務(wù)時(shí),運(yùn)行的文件。

# encoding:utf8
import time
import os
import re
import csv
from shop.jd import JD # 自定義
from shop.tm import TM
from shop.sn import SN
from shop.pdd import PDD
from apscheduler.schedulers.blocking import BlockingScheduler

# import logging
# formats = "%(asctime)s %(name)s %(levelname)s function:%(funcName)s -> :%(message)s"
# logging.basicConfig(format=formats, datefmt='%m/%d/%Y %I:%M:%S %p') # ,handlers=[logging.FileHandler(log_path, 
'a+', 'utf-8')]
# LOGGER = logging.getLogger(__name__)
# LOGGER.setLevel(logging.INFO)
basePath = os.path.dirname(os.path.abspath(__file__)) # 當(dāng)前文件夾
def get_date():
    """獲取日期"""
    timestamp = int(time.time())
    time_local = time.localtime(timestamp) # #時(shí)間戳 轉(zhuǎn) 時(shí)間數(shù)組
    dt = time.strftime("%Y-%m-%d %H:%M:%S",time_local) # #時(shí)間數(shù)組 轉(zhuǎn) 新的時(shí)間格式(2016-05-05 20:28:54)
    return dt
def get_url():
    """讀取商品鏈接
    返回:圖像名,商品名,商品鏈接 元組
    """
    urls = []
    with open(os.path.join(basePath, 'goods.csv'),'r',encoding='utf8') as f:
        f_csv = csv.reader(f)
        next(f_csv) # 返回標(biāo)題,直接到內(nèi)容
        for row in f_csv: # 內(nèi)容
            if row:
                urls.append(row)
    return urls
def go(url):
    '''輸入:鏈接
    輸出:(時(shí)間,標(biāo)題,商品價(jià)格), 文件路徑 元組
    統(tǒng)一價(jià)格輸出,以最低價(jià)格為標(biāo)準(zhǔn),如有團(tuán)購(gòu)和單獨(dú)購(gòu)買以單獨(dú)購(gòu)買為準(zhǔn)
    '''
    result = re.findall('://(.+?).com', url[2])
    if result:
        result = result[0]
        if 'yangkeduo' in result:
            pd = PDD(url[2])
            title,price = pd.main()
        elif 'suning' in result:
            sn = SN(url[2])
            title,price = sn.main()
        elif 'tmall' in result or 'taobao' in result:
            tm = TM(url[2]) # 605030977928:聯(lián)想筆記本 ; 603330883901 華為 mate30 pro ; 523962011119: 酸奶 
            title,price = tm.main()
        elif 'jd' in result:
            jd = JD(url[2]) # 測(cè)試 id:100009083152 商品:聯(lián)想 y9000x 筆記本電腦 2 熱水壺 or 薯?xiàng)l?
            title,price = jd.main()
        else:
            raise TypeError('請(qǐng)檢查輸入的網(wǎng)站鏈接')
        print('%s 標(biāo)題 %s, 價(jià)格(多個(gè)價(jià)格以團(tuán)購(gòu)為準(zhǔn)) %s. '%(result,title,price))
    else:
        raise TypeError('請(qǐng)檢查輸入是否為目標(biāo)網(wǎng)站的商品詳細(xì)頁面鏈接')
    # 文件名
    replace_string = ['.',' ',r'/',r'\\']
    for rs in replace_string:
        url[1] = url[1].replace(rs,'_')
    path = os.path.join(os.path.join(basePath, 'data'), url[1]+'.csv')
    today = get_date() # 日期
    return (today, title, price),path
def addData(row, path):
    """數(shù)據(jù)寫入文件"""
    with open(path,'a+',encoding='utf8') as f:
        fieldnames = ['時(shí)間', '標(biāo)題','價(jià)格']
        writer = csv.DictWriter(f, fieldnames=fieldnames)
        if f.tell() == 0: # 如果內(nèi)容為空則添加標(biāo)題
            writer.writeheader()
        writer.writerow({'時(shí)間': row[0], '標(biāo)題': row[1],'價(jià)格':row[2]})
def main():
    """運(yùn)行程序"""
    urls = get_url()
    for url in urls:
        try:
            row,path = go(url) # 獲取返回信息 
            addData(row,path) # 寫入文件
        except BaseException as e:
            print('請(qǐng)求問題?報(bào)錯(cuò):%s'%e)
if __name__ == '__main__':
    print('時(shí)間',get_date())
    main()
    # scheduler = BlockingScheduler()
    # scheduler.add_job(go,'cron', args=[url],hour='8-23', minute= '5,35' , second='15')
    # # scheduler.add_job(main,'cron', args=[3088512],hour='8-23', minute= 5 , second='15')
    # print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))
    # try:
    #     scheduler.start()
    # except (KeyboardInterrupt, SystemExit):
    #     pass

draw.py

圖像文件生成在 pic 文件中。

# encoding: utf8
from pyecharts import options as opts
from pyecharts.charts import Page, Line
import os
import csv

basePath = os.path.dirname(os.path.abspath(__file__)) # 當(dāng)前文件夾
def line(title,checktime,price) -> Line:
    """繪圖函數(shù)"""
    c = (
        Line()
        .add_xaxis(checktime)
        .add_yaxis(title, price, is_smooth=True)
        .set_global_opts(title_opts=opts.TitleOpts(title="商品價(jià)格"),
                yaxis_opts=opts.AxisOpts(name="元/臺(tái)"),
                xaxis_opts=opts.AxisOpts(name=title,
                axislabel_opts=opts.LabelOpts(formatter="{value}", font_size=12, rotate=30,) # x,y 軸標(biāo)簽
                    )
                )
        )
    return c
def files():
    """
    輸出字典,每一個(gè)鍵值代表一張圖表
    """
    global basePath
    files = {}
    with open(os.path.join(basePath,'goods.csv'),'r',encoding='utf8') as f:
        f_csv = csv.reader(f)
        next(f_csv) # 標(biāo)題
        for row in f_csv: # 內(nèi)容
            if row:
                replace_string = ['.',' ',r'/',r'\\'] # 特殊字符處理
                for rs in replace_string:
                    row[1] = row[1].replace(rs,'_')
                files.setdefault(row[0],[]).append(row[1])
    return files
def draw(files):
    """繪制圖形文件"""
    datapath = os.path.join(basePath,'data')
    picpath = os.path.join(basePath,'pic')
    for k,i in files.items():
        page = Page()
        for n in i:
            try:
                with open(os.path.join(datapath, n +'.csv'),'r', encoding='utf8') as f:
                    f_csv = csv.DictReader(f)
                    price,checktime = [],[]
                    for row in f_csv:
                        checktime.append(row['時(shí)間'])
                        price.append(row['價(jià)格'])
                    title = n
                page.add(line(title,checktime,price)) # 24 發(fā)帖回帖變化圖、近3月變化圖、瀏覽、回復(fù)散點(diǎn)圖
            except:
                print('未制圖:',n)
        page.render(os.path.join(picpath, k +'.html'))
if __name__ == '__main__':
    draw(files())

關(guān)于Python實(shí)現(xiàn)商品價(jià)格監(jiān)控的方法就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI