声明:本博客只是简单的爬虫示范,并不涉及任何商业用途。
一.前言
最近博主在浏览淘宝时突然萌发了一个想爬它的念头,于是说干就干,我便开始向淘宝“下毒手”了。由于本人平时经常喜欢在淘宝上浏览各种手机的信息,于是我便以“手机”为关键词进行搜索,最后我利用爬虫获取了所有相关的手机信息,并对各种厂家生成手机的销量进行了一波可视化,下面是完整的记录过程。
二.爬虫过程
2.1 解决淘宝的登录问题
首先,我在浏览器中打开淘宝,然后登录后以手机为关键词进行搜索,得到如下链接:
https://s.taobao.com/search?q=%E6%89%8B%E6%9C%BA&imgfile=&js=1&stats_click=search_radio_all%3A1&initiative_id=staobaoz_20200911&ie=utf8
但当我用requests库请求该url时,结果却发现要先登录,即会出现下述界面:
这个问题要如何解决呢?我首先想到的是利用cookie,于是我便在登录淘宝时,通过Chrome浏览器的开发者工具获取到了登录淘宝的cookie,然后我将该cookie作为参数传入reqeusts库的相关函数,结果发现成功获取到想要的页面!
2.2 页面URL分析
在页面的下方可以看到手机售卖的页面共有100页,那么要如何获取到对应的页面呢?我先点击下方的按钮获取到了几个页面的url,展示如下:
https://s.taobao.com/search?q=%E6%89%8B%E6%9C%BA&imgfile=&js=1&stats_click=search_radio_all%3A1&initiative_id=staobaoz_20200911&ie=utf8&bcoffset=3&ntoffset=3&p4ppushleft=1%2C48&s=44
https://s.taobao.com/search?q=%E6%89%8B%E6%9C%BA&imgfile=&js=1&stats_click=search_radio_all%3A1&initiative_id=staobaoz_20200911&ie=utf8&bcoffset=0&ntoffset=6&p4ppushleft=1%2C48&s=88
https://s.taobao.com/search?q=%E6%89%8B%E6%9C%BA&imgfile=&js=1&stats_click=search_radio_all%3A1&initiative_id=staobaoz_20200911&ie=utf8&bcoffset=-3&ntoffset=-3&p4ppushleft=1%2C48&s=132
根据观察上述url中变化的只有bcoffset
,ntoffset
以及s
,但是只有最后一个参数s
改变才会使得页面翻转,而最后一个参数s
是递增的,每次增加44,因此我们可以通过改变s来获取翻页的URL。
2.3 数据提取
在淘宝页面右键->查看源代码,可以发现数据数据隐藏在名为g_page_config
的json对象里面:
因此,可以先通过正则表达式将其过滤出来,然后利用json模块将其加载为python对象,之后便可以对其进行数据提取(详细的提取过程参加后面的完整代码),需要提取的数据展示如下:
2.4 爬虫完整流程
综合以上几点,淘宝手机信息爬取的流程图如下图所示:
2.5 爬取程序及结果展示
完整的爬虫程序展示如下:
from bs4 import BeautifulSoup
import requests
import re
import json
import random
import pandas as pd
import traceback
IPRegular = r"(([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5]).){3}([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])"
headers = {
"User-Agent": "换成自己的User-Agent",
"cookie": "换成自己登录的淘宝cookie"
}
def ExtractIP(url="https://ip.ihuan.me/"):
""" 功能:抓取IP,返回IP列表 url:抓取IP的网站 """
IPs = []
response = requests.get(url)
soup = BeautifulSoup(response.content,"lxml")
tds = soup.find_all("a",attrs = { 'target':'_blank'})
for td in tds:
string = td.text
if re.search(IPRegular,string) and string not in IPs:
IPs.append(string)
print(IPs)
return IPs
def Filter(mobile_infos):
""" 功能:过滤出手机的相关信息 mobile_infos: """
mobile_list = [] #存储手机信息的列表
for mobile_info in mobile_infos:
title = mobile_info['raw_title']
price = mobile_info['view_price']
loc = mobile_info['item_loc'].replace(' ','')
shop = mobile_info['nick']
#print(mobile_info['view_sales'])
sales = re.search(r'(\d+.?\d*).*人付款',mobile_info['view_sales']).group(1)
if sales[-1] == '+':#去掉末尾的加号
sales = sales[:-1]
if '万' in mobile_info['view_sales']:
sales = float(sales) * 10000
print(title,price,loc,shop,int(sales),mobile_info['view_sales'])
mobile_list.append([title,price,loc,shop,int(sales)])
return mobile_list
def Saver(mobiles):
""" 功能:保存爬取信息 mobiles:手机信息列表 """
mdata = pd.DataFrame(mobiles,columns=['手机名','价格','店铺位置','店铺名','销量'])
mdata.to_csv('mobile_info.csv',index=False)
def Spider(page_nums = 100):
""" 功能:爬虫主程序 page_nums:待爬取的页数 """
#爬取代理IP
IPs = ExtractIP()
length,mobiles,i = len(IPs),[],0
while i < page_nums:
try:
print('--------------------正在爬取第{}页--------------------'.format(i + 1))
url = "https://s.taobao.com/search?q=%E6%89%8B%E6%9C%BA&imgfile=&commend=all&ssid=s5-e&search_type=item&sourceId=tb.index&spm=a21bo.2017.201856-taobao-item.1&ie=utf8&initiative_id=tbindexz_20170306&bcoffset=3&ntoffset=0&p4ppushleft=1%2C48&data-key=s&data-value={}".format(i*44)
#设置代理ip
index = random.randint(0,length - 1)
proxies = { "http":"{}:8080".format(IPs[index])}
#请求网页
response = requests.get(url,headers=headers,proxies=proxies)
#利用正则表达式获取包含手机信息json数据
match_obj = re.search(r'g_page_config = (.*?)};',response.text)
#将json对象加载为python字典
mobile_infos= json.loads(match_obj.group(1) + '}')['mods']['itemlist']['data']['auctions']
#过滤出字典中的有用信息
mobiles += Filter(mobile_infos)
i += 1
except Exception:
traceback.print_exc()
print('手机信息第{}页爬取失败'.format(i + 1))
i += 1
#保存手机信息为csv文件
Saver(mobiles)
if __name__ == "__main__":
Spider()
利用上述方式将爬取的数据保存为csv文件,部分结果截图展示如下:
三.数据处理及分析
3.1 数据去重
通过爬虫一共获取到4400多条记录,但其中有没有重复数据呢,于是我通过pandas来对其进行重复行统计,结果确实返现不少重复行,对应处理代码如下:
import pandas as pd
mdata = pd.read_csv('mobile_info.csv')
print(mdata[mdata.duplicated()])
""" 手机名 价格 店铺位置 店铺名 销量 61 【限时限量抢】Apple/苹果iPhone SE全网通手机苏宁易购官方旗舰店Store国行正... 3299.00 江苏南京 苏宁易购官方旗舰店 2998 92 糖果手机Sugar Y9指纹识别全网通5 399.00 广东深圳 sugar手机旗舰店 6 93 现货OnePlus/一加 A6010一加6T手机1+6T手机 1439.00 广东深圳 港柏数码 301 136 糖果手机Sugar Y9指纹识别全网通5 399.00 广东深圳 sugar手机旗舰店 6 137 现货OnePlus/一加 A6010一加6T手机1+6T手机 1439.00 广东深圳 港柏数码 301 180 糖果手机Sugar Y9指纹识别全网通5 399.00 广东深圳 sugar手机旗舰店 6 181 现货OnePlus/一加 A6010一加6T手机1+6T手机 1439.00 广东深圳 港柏数码 301 ... ... ... ... ... """
因此我在这里进行了相应的去重处理,代码为:
mdata.drop_duplicates(inplace=True)
3.2 统计各手机的销量
在完成去重后,我对各手机的销量进行了统计,最后利用matplotlib将统计数据绘制成了直方图,下面是对应的结果:
可以看出华为,小米和苹果占据了销量的前三甲。
四.结语
完整项目地址:taobao_mobileInfo_demo
以上便是本文的全部内容,要是决定不错的话就点个赞支持一下吧,你们的支持是博主创作的不竭动力!另外在这里需要说明一下,我爬取的数据可能不齐全,最后的各手机厂家销量展示也不具有权威性,仅仅是博主的自娱自乐,敬请批评指正。