Python爬取多点商城整站步骤介绍:
1、Python开发工具pycharm安装,Python-3.6.4(Mac、Windows)即可,PHPStudy/XMAPP集成环境搭建(其他集成环境也可);
2、展示多点商城设计特点图;
3、列出分析爬取多点整站思维导图;
4、需求分析;
5、爬取操作过程;
6、编写代码;
7、表结构设计,代码经过多次修改健壮无比,导出sql文件使用即可;
8、注意事项(申明)
多点商城设计特点图
① 首先我们先浏览下多点商城页面,展示图如下:
② 我们主要关注爬取页设计结构,对应上图中的分类模块,分类模块包含了多点商城全部数据,我们只爬取分类模块就可以了,展示图如下:
三、列出分析爬取多点整站思维导图
在文章开头列出了很多疑问,我们应该怎么样获取我们需要的数据那,这部分我们用思维导图来列出我们需要做的事情,思维导图会更加清晰的理清我们的思路,思维导图如下:
四、需求分析
多点商城中的商品信息比较全面,符合我们工作需求,多点商城中商品图片很是清晰,商品包括的信息全面:商品名字、商品展示图、商品详情轮播图、商品规格参数、商品介绍图、商品分类、品牌brand、商品唯一对应的skuid、商品分类id、猜你喜欢商品图、商品价格等等。
① 获取到数据录入sql数据表设计展示如下:
② 本地数据展示图
设置好自己的域名以后,可以远程或者本地连接自己的数据库(商品库),终于拥有了属于自己的商品库喽。
五、爬取操作过程
① 获取爬取网站链接多点商城
② 进入分类,分析大分类和小分类之间的联系,并分析我们爬取数据的对象,爬取对象是小分类,截图如下:
③ 我们应该怎么样获取小分类的链接哪,接下来我们展示操作过程,鼠标点击右键查看检查审查元素,获取到的链接地址,操作过程截图如下:
④ 对于审查得到的数据我们应该怎么获取数据哪,接下来我对链接到的数据进行分析,在浏览器中打开我们获取的数据列表如下:
⑤ 接下来就是编写代码的时候,编写代码我放到下部分进行分享
六、撸代码(撸代码是一件很快乐的事)
① 在Ptython3.6.4环境中进行开发的,在开发过程中用到了很多Python包如下:
# urllib请求用到的开发包
from urllib import request
# os是创建文件或者文件夹的开发包
import os
# json处理python对象和字符串之间的转换
import json
# jsonpath获取数据中需求字段的开发包
import jsonpath
# time主要用来设置休眠时间
import time
# ssl验证
import ssl
# selenium自动化,处理动态js
from selenium import webdriver
# pymysql连接数据库包
import pymysql
# lxml解析包
from lxml import etree
② 打开PHPStudy或者XMAPP集成服务器,用pymysql包连接mysql,自动创建数据库、表名、生成我们设定的字段;
③ 我们用urllib包来请求我们审查到的链接,请求到数据并转化成我们需要的json格式;
④ 用jsonpath模块来解析json数据,获取我们需要的字段;
⑤ 用selenium动态获取js数据,并分析获取到数据页数;
⑥ 所有工作准备完毕后,执行成功后,就插入数据表中,并同时把图片保存到本地
附源码
from urllib import request
import os
import json
import jsonpath
import time
import ssl
from selenium import webdriver
import pymysql
from lxml import etree
ssl._create_default_https_context = ssl._create_unverified_context
class PythonSugar():
def __init__(self):
# 爬取分类修改修改:商品列表地址、商品详情地址、存储的商品分类id=11347
self.url = 'https://gatewx.dmall.com/customersite/searchWareByCategory?param={"pageNum":1,"pageSize":41,"venderId":"1","storeId":"108","sort":"1","categoryId":10905,"categoryLevel":3,"cateSource":1,"bizType":"1"}&token=&source=2&tempid=C7B357489E400002B1514BD01B00E270&pubParam={"utmSource":"wxmp"}&_=1512268447989'
self.headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:56.0)'}
self.detailurl = 'https://i.dmall.com/?source_id=wxmp#item/view/item/item:id=1-108-'
# if page == 1:
self.get_connect()
def get_connect(self):
self.tablename = 'duodian'
self.db = pymysql.connect(host='127.0.0.1', user='root', passwd='', db='test', charset='utf8')
self.cur = self.db.cursor()
self.cur.execute('USE test')
try:
# 创建表
self.cur.execute(
'CREATE TABLE ' + self.tablename + ' (id BIGINT(7) NOT NULL AUTO_INCREMENT, title VARCHAR(1000), img VARCHAR(1000), lunfanimg VARCHAR(1000), spec VARCHAR(1000), xcimg VARCHAR(1000), skuid VARCHAR(1000),pimg VARCHAR(1000), plunfanimg VARCHAR(1000),pxcimg VARCHAR(1000) ,categoryid VARCHAR(1000),price VARCHAR(1000),brandname VARCHAR(1000),categoryname VARCHAR(1000),created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(id))')
except pymysql.err.InternalError as e:
print(e)
# 修改表字段
self.cur.execute('ALTER DATABASE test CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE title title VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE img img VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE lunfanimg lunfanimg VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE spec spec VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE xcimg xcimg VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE skuid skuid VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
# 存储本地
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE pimg pimg VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE plunfanimg plunfanimg VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE pxcimg pxcimg VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE categoryid categoryid VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE price price VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE brandname brandname VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE categoryname categoryname VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
def get_html(self):
req = request.Request(self.url,headers=self.headers)
response = request.urlopen(req)
html = response.read()
return html
def get_mkdir(self):
jsonobj = json.loads(self.get_html().decode('utf-8'))
# 列表页 - 图片
imgList = jsonpath.jsonpath(jsonobj, '$..img')
# 列表页 - 价格
pricelist = jsonpath.jsonpath(jsonobj, '$..price')
# 列表页 - 商品名
titleList = jsonpath.jsonpath(jsonobj, '$..title')
# 列表页 - 商品id -- skuId
skuIdList = jsonpath.jsonpath(jsonobj, '$..promotionInfo.skuId')
# 商品价格
priceList = jsonpath.jsonpath(jsonobj, '$..price')
# 商品品牌
brandList = jsonpath.jsonpath(jsonobj, '$..brandName')
# 商品分类
categoryList = jsonpath.jsonpath(jsonobj, '$..thirdCatName')
listdata = zip(titleList, imgList, pricelist,skuIdList,priceList,brandList,categoryList)
for item in listdata:
print(item)
# 替换'/'
import re
strinfo = re.compile('/')
itemdir = strinfo.sub('-', item[0])
print(itemdir)
time.sleep(1)
# 商品名称目录
if not os.path.exists(itemdir):
os.makedirs(itemdir)
else:
print(itemdir + ' -- 目录已存在!')
self.dataurl = ''
# 存储本地主页图片链接地址
self.pimg = ''
# 列表页 - 图片
# 文件夹和文件命名不能出现这9个字符:/ \ : * " < > | ?
if os.path.exists( itemdir + '/' + item[1][-20:].replace('/','-').replace('\\','-').replace(':','-').replace('*','-').replace('"','-').replace('<','-').replace('>','-').replace('|','-').replace('?','-') + '.webp'):
print('文件已存在!')
# return 0
else:
if item[1].startswith('//'):
self.dataurl = "http:" + item[1]
else:
self.dataurl = item[1]
try:
req = request.Request(self.dataurl, headers=self.headers)
reponse = request.urlopen(req)
get_img = reponse.read()
self.pimg = '/pimgs/' + itemdir + '/' + self.dataurl[-20:].replace('/','-').replace('\\','-').replace(':','-').replace('*','-').replace('"','-').replace('<','-').replace('>','-').replace('|','-').replace('?','-') + '.webp'
with open( itemdir + '/' + self.dataurl[-20:].replace('/','-').replace('\\','-').replace(':','-').replace('*','-').replace('"','-').replace('<','-').replace('>','-').replace('|','-').replace('?','-') + '.webp', 'wb') as fp:
fp.write(get_img)
except Exception as e:
print(e)
# 详情目录
if not os.path.exists(itemdir + '/详情'):
os.makedirs(itemdir + '/详情')
else:
print('详情' + ' -- 目录已存在!')
driver = webdriver.PhantomJS(executable_path='./phantomjs-2.1.1-macosx/bin/phantomjs')
time.sleep(5)
driver.get(self.detailurl + str(item[3]))
time.sleep(5)
driver.find_element_by_class_name('tipinfo').click()
time.sleep(5)
html = etree.HTML(driver.page_source)
imglist = html.xpath('//img/@src')
print(self.detailurl + str(item[3]))
# 轮番图
lunfantu = html.xpath('//img[@class="detail-img"]/@src')
# 猜你喜欢
# like = html.xpath('//img[@class="J_ItemImage recommend-img"]/@src')
# 商品宣传图
xuanchuan = html.xpath('//div[@class="J_descriptionDetail parameter"]//img/@src')
# 规格
# 左边的参数名
leftspec = html.xpath('//div[@class="left attr_key border-1px border-r border-b"]/text()')
# 右边的参数值
rightspec = html.xpath('//div[@class="left attr_value border-1px border-b"]/span/text()')
spec = zip(leftspec,rightspec)
# time.sleep(5)
# print(driver.page_source)
print(str(item[3]))
print("-------------------------- 轮播图 --------------------------------")
print(lunfantu)
print("--------------------------- 规格 ---------------------------------")
print(spec)
print("-------------------------- 介绍图 ---------------------------------")
print(xuanchuan)
print("-------------------------- 主页图 ---------------------------------")
print(self.dataurl)
for simple in imglist:
if not os.path.exists( itemdir + '/详情/' + simple[-20:].replace('/','-').replace('\\','-').replace(':','-').replace('*','-').replace('"','-').replace('<','-').replace('>','-').replace('|','-').replace('?','-') + '.webp'):
request.urlretrieve(simple, itemdir + '/详情' + '/' + simple[-20:].replace('/','-').replace('\\','-').replace(':','-').replace('*','-').replace('"','-').replace('<','-').replace('>','-').replace('|','-').replace('?','-') + ".webp")
print("正在下载......")
else:
print('文件已存在!')
# NOT
# NULL
# AUTO_INCREMENT, title
# VARCHAR(1000), img
# VARCHAR(1000), lunfanimg
# VARCHAR(1000), spec
# VARCHAR(1000), xcimg
# VARCHAR(1000),
# 插入数据库l
# 判断数据库是否有skuId,有就不插入,无则插入
result = self.cur.execute("select skuid from duodian WHERE skuid=" + str(item[3]))
print(str(result) + '-----------------------')
if result:
print("数据库里面存在此数据")
else:
# 不存在,存数据
lunfantu1 = {}
specpagram ={}
xuanchuan1 = {}
# 轮番图
for index1, item1 in enumerate(lunfantu):
lunfantu1[index1] = item1
# 规格
speckey = 0
for itemspec in spec:
specvalue = str(itemspec[0]) + '-' + str(itemspec[1])
specpagram[str(speckey)] = specvalue
speckey += 1
# 介绍图
for index3, item3 in enumerate(xuanchuan):
xuanchuan1[index3] = item3
# 存储本地图片链接地址
plunfantu = {}
pxuanchuan = {}
for pindex1, pitem1 in enumerate(lunfantu):
plunfantu[pindex1] = '/pimgs/' + itemdir + '/详情/' + pitem1[-20:].replace('/','-').replace('\\','-').replace(':','-').replace('*','-').replace('"','-').replace('<','-').replace('>','-').replace('|','-').replace('?','-') + '.webp'
for pindex2, pitem2 in enumerate(xuanchuan):
pxuanchuan[pindex2] = '/pimgs/' + itemdir + '/详情/' + pitem2[-20:].replace('/','-').replace('\\','-').replace(':','-').replace('*','-').replace('"','-').replace('<','-').replace('>','-').replace('|','-').replace('?','-') + '.webp'
self.cur.execute(
'INSERT INTO ' + self.tablename + ' (title, img, lunfanimg, spec, xcimg,skuid,pimg, plunfanimg, pxcimg,categoryid,price,brandname,categoryname) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s,%s, %s, %s,%s)',
(itemdir, self.dataurl, json.dumps(lunfantu1,ensure_ascii=False), json.dumps(specpagram,ensure_ascii=False), json.dumps(xuanchuan1,ensure_ascii=False),str(item[3]),self.pimg,json.dumps(plunfantu,ensure_ascii=False),json.dumps(pxuanchuan,ensure_ascii=False),'10905','%.2f'%(item[4]/100),str(item[5]),str(item[6])))
self.cur.connection.commit()
print("------------------------ 插入成功 ----------------------------------")
if __name__ == "__main__":
# for page in range(1,3):
pythonSugar = PythonSugar()
pythonSugar.get_mkdir()
print(" -- 爬取完毕 -- ")
七、表结构设计
表结构中字段的设计是我在代码中自动生成的,如果某个字段不符合我们的需求,可以任意修改代码中药修改的字段即可,运行程序就能修改成功,无须在mysql数据库中手动操作,主要用到了游标对象,这样设计表结构,简单快捷,设计如下:
# 修改表字段
self.cur.execute('ALTER DATABASE test CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE title title VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE img img VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE lunfanimg lunfanimg VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE spec spec VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE xcimg xcimg VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE skuid skuid VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
# 存储本地
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE pimg pimg VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE plunfanimg plunfanimg VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE pxcimg pxcimg VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE categoryid categoryid VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE price price VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE brandname brandname VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
self.cur.execute(
'ALTER TABLE ' + self.tablename + ' CHANGE categoryname categoryname VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
数据表结构展示图: