美文网首页Python3自学 爬虫实战python自学Python
教隔壁小姐姐搭建Python爬虫比价网站

教隔壁小姐姐搭建Python爬虫比价网站

作者: Ackerzy | 来源:发表于2018-08-14 01:48 被阅读212次

    隔壁的小姐姐让我和她七夕呆一天,我想一天那么长,光聊天肯定很无聊,那么做点什么好呢?

    想到这几天正好在学Python爬虫,于是我精心准备了搭建Python爬虫网站的教程,教小姐姐用Python,这样肯定不会无聊了O(∩_∩)O哈哈~

    最终效果展示

    01 基础知识

    为了让小姐姐能听懂,我提前跟她说了要预习的知识。

    微信图片

    当然,小姐姐也是有一定python基础的,有了上面的准备,相信我们一定能做一个深入的学习讨论。

    02 实现思路

    这个项目主要由三个部分组成

    • 爬虫:爬取京东、1号店和淘宝的商品信息实现价格比较
    • Flask:运用Flask构建Web应用,显示爬虫结果
    • pythonanywhere:通过pythonanywhere将Web应用部署到云
    实现思路

    03 爬虫

    第一步是用python爬虫脚本抓取网页上的商品信息,这里我们主要对京东、1号店和淘宝的商品信息进行爬取。不同的网页需要进行不同的分析,但方法都是大同小异的。我们先以1号店为例看看如何编写爬虫代码。

    一、爬取1号店的商品数据

    开始之前我们需要引入下面的python库:

    import requests
    from lxml import html
    import urllib.parse
    

    接下来,我们定义函数crawler:

    def crawler(word, products_list=[]):
    

    这里的word就是我们需要搜索商品名称,而products_list用来保存我们的爬取结果。

    word = urllib.parse.quote(word)
    

    当我们查询的商品名称含有中文时,是要对其进行编码处理的,urllib.parse.quote()函数可以帮助实现这一点。
    当我们在1号店搜索商品名称时,其实是发起了一个url请求,这个url中包含了我们要查询的信息。因此我们需要将word参数加入到url中。

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

    接下来的三步顺其自然,获取html源码,将html源码转换为xpath对象,然后在html树状结构中寻找包含商品信息的节点。

    # 获取html源码
    html_doc = requests.get(url).text
    
    # xpath对象
    selector = html.fromstring(html_doc)
    
    # 商品列表
    ul_list = selector.xpath('//div[@id="itemSearchList"]/div')
    

    得到了当前页面的商品列表之后,我们需要对其进行遍历获取其中每个商品的名称、价格、购买链接和店铺信息。

        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')
            # 价格
            price = li.xpath('div//p[@class="proPrice"]/em/@yhdprice')
            # 店铺
            store = li.xpath('div//p[@class="storeName limit_width"]/a/@title')
    

    最后将我们爬取到的结果,存入products_list中为最后的价格比较做准备。

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

    二、爬取京东的商品数据

    京东商品信息的爬取与1号店十分相似,需要注意的是京东网页获取html信息后,需要进行utf-8编码才能正常显示页面。
    直接上源码:

    import requests
    from lxml import html
    
    
    def crawler(word, products_list=[]):
        """ 爬取京东的商品数据 """
        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')
    
        # 解析对应的标题,价格,链接,店铺
        for li in ul_list:
    
            # 标题
            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')
    
            # 价格
            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寻找包含商品信息的节点,查看网页源代码会发现根本就没有包含商品信息的html标签。这主要是因为淘宝是通过传递json数据来更新页面数据的。

    因此这里的url不是一个网址,而是一个api接口:

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

    当我们得到了淘宝传递的json数据后,后面的过程就很简单了,在json中寻找目标信息要比在html树状结构中寻找方便多了。

    源码如下:

    import requests
    import urllib.parse
    
    
    def crawler(word, products_list=[]):
        """ 爬取淘宝网的商品数据 """
        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)
    
    

    四、综合比价

    综合比价需要我们导入前面三个爬虫脚本,并按价格由低到高的排序得到最终结果。

    from crawler_jd import  crawler as jd
    from crawler_yhd import crawler as yhd
    from crawler_taobao import crawler as taobao
    
    
    def main(word):
        """ 比价工具整合 """
        products_list = []
    
        # 京东数据
        print('京东网数据爬取完成')
        jd(word, products_list)
    
        # 1号店数据
        print('1号店数据爬取完成')
        yhd(word, products_list)
    
        # 淘宝数据
        print('淘宝网数据爬取完成')
        taobao(word, products_list)
    
        print('-------------------------开始排序---------------------------------')
    
        # 排序书的数据
        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提供了一组模块,可以帮助我们构建服务器端Web应用,由于我们的爬虫网站功能简单,所以Flask这个轻量级的框架就够了。

    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 = '比价结果'
        titles = ('商品', '价格', '链接', '店铺', '来源')
        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应用的初始页面是entry.html,并向其中传入了我们想要显示的信息。
    entry.html源码:

    {% extends 'base.html' %}
    
    {% block body %}
    
    <h2>{{ the_title }}</h2>
    
    <form method='POST' action='/compare'>
    <table>
    <p>请输入想要比价的商品:</p>
    <tr><td>商品:</td><td><input name='word' type='TEXT' width='60'></td></tr>
    </table>
    <p>准备好了,点击这里:</p>
    <p><input value='Do it!' type='SUBMIT'></p>
    </form>
    
    {% endblock %}
    

    search_products接收了entry.html传入的word参数,并交由crawler_product进行爬虫,最后向results.html传递爬虫结果。
    results.html源码:

    {% extends 'base.html' %}
    
    {% block body %}
    
    <h2>{{ the_title }}</h2>
    
    <p>你提交的商品名称:</p>
    <table>
    <tr><td>关键字:</td><td>{{ the_word }}</td></tr>
    </table>
    
    <p>下面是 "{{ the_word }}" 的搜索比价结果:</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 %}
    

    到这里我们所有的代码都已经准备完毕,我们可以看看整个项目的源码结构:

    项目结构

    crawler_jd.pycrawler_yhd.pycrawler_taobao.py分别为三个网页的爬虫脚本,通过crawler_product.py进行综合比较。

    Flask_PriceCompaer.py是Flask Web应用核心代码,创建Flask对象并传递数据。

    templates文件夹下的base.html是前端页面的基模板,entry.html继承了基模板负责网站进入页面的显示,results.htmlentry.html类似,负责网站结果页面的显示。
    static文件夹下的hf.css就是普通的css文件,负责页面的美化。

    我们可以运行Flas_PriceCompaer.py来看看网站的整体效果。

    页面入口:

    entry

    查询结果:

    results

    源码下载

    05 pythonanywhere

    最后,只要10分钟就可以把我们的Web应用部署到云上,通过公网快捷地访问Python爬虫比价网站。

    一、注册Pythonanywhere

    将网站源代码打包压缩,访问pythonanywhere.com,并进行注册。

    二、将文件上传到云

    文件上传

    三、解压缩和安装代码

    文件上传后,点击Open Bash console here,Pythonanywhere会弹出Linux控制台,我们执行两条命令:
    unzip PriceCompaer.zip
    mv PriceCompaer/* mysite/
    将web应用的代码安装到mysite文件夹。

    四、创建一个初始Web应用

    创建Web应用

    点击Add a new web app后,一路next,并选择web framework为Flask以及相应python版本。

    五、配置Web应用

    接下来我们点击下图提示的位置:

    5.PNG

    修改from flask_app import app as application,将flask_app修改为我们自己的Flask Web应用代码,如Flask_PriceCompaer。同时,我们也要查看Flask_PriceCompaer.py 文件,确保最后没有app.run()

    六、运行

    配置完成后,就可以点击那个绿色的Reload按钮开始运行了。

    PS:要提醒的是,pythonanywhere免费版只能访问特定的网站,所以爬虫程序无法运行,想体检完整结果请自行升级收费版。

    06 写在最后

    这篇文章主要是记录自己的实现思路以及方法,其中的原理并没有进行详细的阐述。虽然主要是因为那样写的话太累了,但更重要的是,爬虫、Flask和pythonanywhere网上都有大量的教程,在大神们的教程里浪费时间才更有意义。

    相关文章

      网友评论

      • mmp1994:只爬了一页是吧?
        mmp1994:@Ackerzy 好的,谢谢
        Ackerzy:@lsh呵呵 恩 只爬了一页,没有加多线程,只爬一页也有点慢
      • Kr2enn:学习学习!
      • liugensite:这就是传说中的大佬吧
      • 974c68788233:占一楼赞赞赞。

      本文标题:教隔壁小姐姐搭建Python爬虫比价网站

      本文链接:https://www.haomeiwen.com/subject/yhmpbftx.html