隔壁的小姐姐让我和她七夕呆一天,我想一天那么长,光聊天肯定很无聊,那么做点什么好呢?
想到这几天正好在学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.py
、crawler_yhd.py
、crawler_taobao.py
分别为三个网页的爬虫脚本,通过crawler_product.py
进行综合比较。
Flask_PriceCompaer.py
是Flask Web应用核心代码,创建Flask对象并传递数据。
templates
文件夹下的base.html
是前端页面的基模板,entry.html
继承了基模板负责网站进入页面的显示,results.html
与entry.html
类似,负责网站结果页面的显示。
static
文件夹下的hf.css
就是普通的css文件,负责页面的美化。
我们可以运行Flas_PriceCompaer.py
来看看网站的整体效果。
页面入口:
查询结果:
05 pythonanywhere
最后,只要10分钟就可以把我们的Web应用部署到云上,通过公网快捷地访问Python爬虫比价网站。
一、注册Pythonanywhere
将网站源代码打包压缩,访问pythonanywhere.com,并进行注册。
二、将文件上传到云
三、解压缩和安装代码
文件上传后,点击Open Bash console here
,Pythonanywhere会弹出Linux控制台,我们执行两条命令:
unzip PriceCompaer.zip
mv PriceCompaer/* mysite/
将web应用的代码安装到mysite
文件夹。
四、创建一个初始Web应用
点击Add a new web app
后,一路next,并选择web framework为Flask以及相应python版本。
五、配置Web应用
接下来我们点击下图提示的位置:
修改from flask_app import app as application
,将flask_app
修改为我们自己的Flask Web应用代码,如Flask_PriceCompaer
。同时,我们也要查看Flask_PriceCompaer.py
文件,确保最后没有app.run()
。
六、运行
配置完成后,就可以点击那个绿色的Reload
按钮开始运行了。
PS:要提醒的是,pythonanywhere免费版只能访问特定的网站,所以爬虫程序无法运行,想体检完整结果请自行升级收费版。
06 写在最后
这篇文章主要是记录自己的实现思路以及方法,其中的原理并没有进行详细的阐述。虽然主要是因为那样写的话太累了,但更重要的是,爬虫、Flask和pythonanywhere网上都有大量的教程,在大神们的教程里浪费时间才更有意义。