鱼C论坛

 找回密码
 立即注册
查看: 3467|回复: 0

[技术交流] 有没有大佬爬过京东手机商品的id,看了下面的代码,自己太水了,实在是提炼不出了。

[复制链接]
发表于 2017-10-12 22:34:47 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
  1. # _*_ coding:utf-8 _*_
  2. import requests
  3. import json
  4. from urllib.parse import quote
  5. from bs4 import BeautifulSoup
  6. import os
  7. import re
  8. import time
  9. import datetime
  10. from random import choice
  11. import traceback
  12. import csv

  13. """
  14. 京东爬虫:抓取京东手机类别下的所有型号的产品信息(基本信息+相对属性+绝对属性+图片)、评论信息

  15. productId 和 skuId:

  16. 字段:
  17. 基本信息:所属分类名称,分类ID,店铺链接,productId,小标题,价格,

  18. 相对属性:


  19. 图片:保存到:分类名称/商品id/  目录下


  20. @API:
  21. 1. 产品介绍的富文本:https://cd.jd.com/description/channel?skuId=3564140&mainSkuId=3564140&cdn=2&callback=showdesc
  22. 2. 产品配件: https://c.3.cn/recommend?callback=handleComboCallback&methods=accessories&p=103003&sku=3564140&cat=9987%2C653%2C655&lid=1&uuid=484377010&pin=&ck=pin%2CipLocation%2Catw%2Caview&lim=5&cuuid=484377010&csid=122270672.70.484377010%7C21.1500617159&_=1500621893531
  23. 3. 优惠套装:https://c.3.cn/recommend?callback=jQuery8538482&sku=3564140&cat=9987%2C653%2C655&area=1_72_2799_0&methods=suitv2&count=6&_=1500621893408
  24. 4. 产品评价统计数据:https://club.jd.com/comment/productCommentSummaries.action?referenceIds=3564140&callback=jQuery8710223&_=1500621893394
  25. 5. 产品价格:https://p.3.cn/prices/mgets?callback=jQuery366476&type=1&area=1_72_2799_0&pdtk=&pduid=484377010&pdpin=&pin=null&pdbp=0&skuIds=J_3564140&ext=11000000&source=item-pc
  26. 6. 增值服务及配送方式:https://c0.3.cn/stock?skuId=3564140&area=1_72_2799_0&venderId=1000000904&cat=9987,653,655&buyNum=1&choseSuitSkuIds=&extraParam={%22originid%22:%221%22}&ch=1&fqsp=0&pduid=484377010&pdpin=&callback=jQuery3612846
  27. 7. 当前产品评论:https://club.jd.com/comment/skuProductPageComments.action?callback=fetchJSON_comment98vv84200&productId=3846673&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1
  28. """


  29. class Jingdong():
  30.     # url获取所有手机品牌id和名称json
  31.     url = 'https://list.jd.com/list.html?cat=9987,653,655&sort=sort_rank_asc&trans=1&md=1&my=list_brand'
  32.     brands = {}
  33.     brands['url'] = {}  # 存储与品牌相关的信息
  34.     items = []      # 存储所有手机的URL
  35.     path = ''  # 当前图片存储路径
  36.     item_path = ''

  37.     itemIDS = {}  # 爬取过的产品的id作为键,值为1

  38.     user_agents = [
  39.         'Mozilla/5.0 (Windows; U; Windows NT 5.2) Gecko/2008070208 Firefox/3.0.1',
  40.         'Mozilla/5.0 (Windows; U; Windows NT 5.1) Gecko/20070309 Firefox/2.0.0.3',
  41.         'Mozilla/5.0 (Windows; U; Windows NT 5.1) Gecko/20070803 Firefox/1.5.0.12',
  42.         'Opera/9.27 (Windows NT 5.2; U; zh-cn)',
  43.         'Mozilla/5.0 (Windows; U; Windows NT 5.2) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13',
  44.         'Mozilla/5.0 (iPhone; U; CPU like Mac OS X) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/4A93 ',
  45.         'Mozilla/5.0 (Windows; U; Windows NT 5.2) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 ',
  46.         'Mozilla/5.0 (Linux; U; Android 3.2; ja-jp; F-01D Build/F0001) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13 ',
  47.         'Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; ja-jp) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7',
  48.         'Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; da-dk) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5 ',
  49.         'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-US) AppleWebKit/530.9 (KHTML, like Gecko) Chrome/ Safari/530.9 ',
  50.         'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11',
  51.         'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)',
  52.         'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Ubuntu/11.10 Chromium/27.0.1453.93 Chrome/27.0.1453.93 Safari/537.36',
  53.         'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36',
  54.         'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36'
  55.     ]
  56.     def __init__(self):

  57.         text = json.loads(requests.get(self.url,headers=self.get_user_hearder()).text)

  58.         for brand in text['brands']:
  59.             url = 'https://list.jd.com/list.html?cat=9987,653,655&ev=exbrand_' + str(brand['id'])+'&sort=sort_rank_asc&trans=1&JL=3_'+quote(brand['name'])
  60.             self.brands['url'][brand['name']] = url  # 存储所有品牌的 {名称:URL} 字典

  61.             # data = {}
  62.             # data['id'] = brand['id']
  63.             # data['name'] = brand['name']
  64.             # data['pinyin'] = brand['pinyin']
  65.             # data['logo'] = brand['logo']
  66.             # data['url'] = url

  67.             # requests.post('127.0.0.1:8000/jingdong/', data=data,headers=self.get_user_hearder())


  68.     def get_user_hearder(self):
  69.         headers = {}
  70.         headers['User-Agent'] = choice(self.user_agents)
  71.         return headers


  72.     def parse_brand(self):
  73.         """
  74.         遍历所有的品牌的URL,分别爬取所有品牌下的所有型号的手机(加上分页),并存储图片到相应品牌命名的文件夹下
  75.         """
  76.         for name in self.brands['url']:
  77.             print('当前类别:'+name)
  78.             self.path = name      # brands['url']字典的键是品牌的名称,值是该品牌的URL
  79.             if not os.path.exists(self.path):
  80.                 os.mkdir(self.path)
  81.             brand_url = self.brands['url'][name]


  82.             # 爬取该品牌下所有手机的信息
  83.             while True:
  84.                 soup = BeautifulSoup(requests.get(brand_url,headers=self.get_user_hearder()).text)
  85.                 lis = soup.find_all("li",attrs={"class":"gl-item"}) # 抓该分类下的所有产品

  86.                 self.items.clear()
  87.                 for li in lis:
  88.                     self.items.append("http:"+str(li.find("a").get('href')))


  89.                 for item_url in self.items:
  90.                     print("当前商品:"+item_url)
  91.                     try:
  92.                         html = requests.get(item_url,headers=self.get_user_hearder())
  93.                         soup = BeautifulSoup(html.text)
  94.                         item_id = re.sub("\D", "", item_url)
  95.                         try:
  96.                             self.item_path = os.path.join(self.path,str(item_id))
  97.                             if not os.path.exists(self.item_path):
  98.                                 os.mkdir(self.item_path)

  99.                             params = self.getParams(soup,item_id) # 获取参数并保存,绝对属性
  100.                             commentMetas = self.getCommMeta(item_id) # 获取评价的相对属性
  101.                             comments = self.getComments(item_id) # 获取100页评价
  102.                             images = self.getImages(soup,self.item_path, item_id) # 获取相片并保存,照片

  103.                             with open('products.csv', 'a') as f:  #
  104.                                 f.write(name+','+str(item_id)+','+params['skuName']+','+ params['price']+','+commentMetas['goodRateShow']+','+commentMetas['poorRateShow']
  105.                                     +','+commentMetas['commentCount']+','+commentMetas['goodCount']+","+commentMetas['generalCount']+','+commentMetas['poorCount'])

  106.                                 for hotTag in list(commentMetas['hotCommentTags']):
  107.                                     f.write(','+hotTag['name']+":"+str(hotTag['count']))

  108.                                 f.write('\n')



  109.                             with open(name+'/' + str(item_id)+'_propertys.csv','w') as f:
  110.                                 for key in params['paramsList'].keys():
  111.                                     f.write(key+','+params['paramsList'][key]+'\n')


  112.                             with open(name+'/' + str(item_id)+'_comments.csv','w') as f:
  113.                                 try:
  114.                                     for comm in comments['goodComments']:

  115.                                         f.write(str(comm['cmid'])+','+str(comm['guid'])+','+comm['nickname']+','+comm['score']+','+'good,'+comm['creationTime']+','+comm['content'])
  116.                                         if 'commentTags' in comm.keys():
  117.                                             for commentTag in comm['commentTags']:
  118.                                                 f.write(','+commentTag['name'])
  119.                                         f.write('\n')   

  120.                                 except:
  121.                                     pass
  122.                                 try:
  123.                                     for comm in comments['geneComments']:

  124.                                         f.write(str(comm['cmid'])+','+str(comm['guid'])+','+comm['nickname']+','+comm['score']+','+'gene,'+comm['creationTime']+','+comm['content'])
  125.                                         if 'commentTags' in comm.keys():
  126.                                             for commentTag in comm['commentTags']:
  127.                                                 f.write(','+commentTag['name'])
  128.                                         f.write('\n')
  129.                                 except:
  130.                                     pass
  131.                                 try:
  132.                                     for comm in comments['badComments']:

  133.                                         f.write(str(comm['cmid'])+','+str(comm['guid'])+','+comm['nickname']+','+comm['score']+','+'bad,'+comm['creationTime']+','+comm['content'])
  134.                                         if 'commentTags' in comm.keys():
  135.                                             for commentTag in comm['commentTags']:
  136.                                                 f.write(','+commentTag['name'])
  137.                                         f.write('\n')   

  138.                                 except:
  139.                                     pass                    

  140.                         except Exception as e:
  141.                             # 每个商品,解析错误的时候,记录日志
  142.                             with open('item_exception.log','a') as f:
  143.                                 # 格式:当前时间,所属类别,产品id,错误原因
  144.                                 f.write(str(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ","+self.path + ","+ str(item_id) + ","+str(e)+"\n")
  145.                                 print(str(e))

  146.                         time.sleep(2)   # 休息2秒
  147.                     except Exception as e:
  148.                         with open('item_error.log','a') as f:
  149.                             # 格式:当前时间,所属类别,产品id,错误原因
  150.                             f.write(str(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ","+item_url +str(e)+"\n")
  151.                             print(str(e))


  152.                 href = soup.find("a",attrs={"class":"pn-next"}) # 下一页

  153.                 if href:
  154.                     brand_url = 'https://list.jd.com'+href.get('href')
  155.                 else:
  156.                     break

  157.                 print('下一页')

  158.             # break


  159.     def getCommJson(self,productId, page=0,score=0):
  160.         """
  161.         获取评论的Json数据:
  162.         score=0为全部,1为差评,2为中评,3为好评
  163.         sortType=6为按时间排序,5为推荐排序
  164.         isShadowSku 是否不只显示当前商品的评论,默认是 0否, 1为是
  165.         获取到json后,京东解析json的js的URL:https://static.360buyimg.com/item/default/1.0.32/components/comment/??comment.js
  166.         """
  167.         #productPageComments
  168.         commUrl="http://sclub.jd.com/comment/skuProductPageComments.action?productId="+str(productId)+"&score="+ str(score)+ "&sortType=6&pageSize=10&isShadowSku=0&page=" + str(page)

  169.         # &callback=fetchJSON_comment98vv83110
  170.         html=requests.get(commUrl,headers=self.get_user_hearder()).text
  171.         # lsize=html.find('{')
  172.         # rsize=html.rfind('}')+1

  173.         # commentJson=json.loads(html[lsize:rsize])
  174.         try:
  175.             json_content = None
  176.             # json_content = json.loads(re.search(r'(?<=\().*(?=\);)',html).group(0))
  177.             json_content = json.loads(html)
  178.         except Exception as e:
  179.             print(traceback.format_exc())
  180.         time.sleep(0.01)
  181.         return json_content


  182.     def getParams(self,soup,productId):
  183.         """
  184.         保存基本参数
  185.         """
  186.         params = {}
  187.         params['price']=self.getPrice(productId)    #获取商品价格
  188.         # skuName=soup.find("div",attrs={"class":"sku-name"}).string    #获取手机的标题
  189.         skuName=soup.find("div",attrs={"id":"name"})
  190.         if skuName is None:
  191.             skuName=soup.find("div",attrs={"class":"sku-name"}).get_text()
  192.         else:
  193.             skuName=skuName.h1.get_text()

  194.         params['skuName'] = skuName.strip()

  195.         paramsList={}
  196.         #获取单反相机的参数
  197.         table=soup.find("table",attrs={"class":"Ptable"})
  198.         if table is not None:
  199.             tds=table.find_all("td",attrs={"class":"tdTitle"})
  200.             for td in tds :
  201.                 tdTitle = td.get_text()
  202.                 tdContent = td.next_sibling.get_text()
  203.                 #paramfile.write(tdTitle+","+tdContent+"\n") #保存绝对属性值
  204.                 paramsList[tdTitle]=tdContent
  205.         else:
  206.             #获取手机的参数:绝对属性
  207.             divSoup=soup.find("div",attrs={"class":"Ptable"})
  208.             divs=divSoup.find_all("div",attrs={"class":"Ptable-item"})
  209.             for dls in divs :
  210.                 dts = dls.find_all('dt');
  211.                 dds = dls.find_all("dd")
  212.                 for dt,dd in zip(dts,dds):
  213.                     # paramfile.write(dt.get_text()+","+dd.get_text()+"\n") #保存绝对属性值
  214.                     paramsList[dt.get_text()]=dd.get_text()
  215.         params['paramsList'] = paramsList
  216.         return params


  217.     def getPrice(self,productId):   #根据productId获取商品价格
  218.         url="https://p.3.cn/prices/mgets?type=1&area=1_72_2799_0&pdtk=&pduid=484377010&pdpin=&pin=null&pdbp=0&skuIds=J_"+str(productId)+"&ext=11000000&source=item-pc"
  219.         html=requests.get(url,headers=self.get_user_hearder()).text
  220.         json2=json.loads(html)
  221.         return json2[0]["p"]


  222.     def getImages(self, soup, item_path, item_id):  #获取图片,并保存
  223.         imgs=soup.find("div",attrs={"id":"spec-list"})
  224.         images = []
  225.         if not imgs:
  226.             return images

  227.         imgs = imgs.find_all("img")

  228.         i=1
  229.         for img in imgs:
  230.             try:
  231.                 imgUrl="http:"+str(img.get("src"))

  232.                 lsize=imgUrl.find("/n5/")       #手机的imageUrl变化
  233.                 rsize=imgUrl.find("_jfs")
  234.                 imgUrl=imgUrl[:lsize]+"/n1/s450x450"+imgUrl[rsize:] #修改图片的URL,获取高清的图片而不是缩略图

  235.                 # lsize=imgUrl.find("/n5/")     #单反相机的imageUrl变化
  236.                 # imgUrl=imgUrl[:lsize]+"/n1/"+imgUrl[lsize+4:] #修改图片的URL,获取高清的图片而不是缩略图

  237.                 images.append(imgUrl)

  238.                 image=requests.get(imgUrl, stream=True,headers=self.get_user_hearder())
  239.                 with open(item_path+"/" + str(item_id) + "_" + str(i)+".jpg","wb")  as jpg:#保存图片
  240.                     for chunk in image:
  241.                         jpg.write(chunk)
  242.                 i=i+1
  243.             except:
  244.                 traceback.print_exc()

  245.         return images


  246.     def getCommMeta(self,item_id):
  247.         """
  248.         获取相对属性,买家印象,评论总结
  249.         """
  250.         commentJson = self.getCommJson(item_id)
  251.         # https://club.jd.com/comment/skuProductPageComments.action
  252.         # ?callback=fetchJSON_comment98vv40836&productId=4669576&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1
  253.         # &callback=jQuery3649390&_=1500941065939
  254.         # https://club.jd.com/comment/productCommentSummaries.action?referenceIds=3564110

  255.         commentMetas = {}

  256.         commentMetas['goodRateShow'] = str(commentJson["productCommentSummary"]["goodRateShow"]) # 好评率
  257.         commentMetas['poorRateShow'] = str(commentJson["productCommentSummary"]["poorRateShow"]) # 差评率
  258.         commentMetas['commentCount'] = str(commentJson["productCommentSummary"]["commentCount"])    #评论数
  259.         commentMetas['goodCount'] = str(commentJson["productCommentSummary"]["goodCount"])      #好评数
  260.         commentMetas['generalCount'] = str(commentJson["productCommentSummary"]["generalCount"])    #中评数
  261.         commentMetas['poorCount'] = str(commentJson["productCommentSummary"]["poorCount"])      #差评数

  262.         # 买家印象
  263.         commentMetas['hotCommentTags'] = commentJson["hotCommentTagStatistics"]

  264.         return commentMetas

  265.     def getComments(self,item_id):
  266.         """
  267.         获取该产品的好评,中评,差评各100页评论数据
  268.         """
  269.         comments = {}
  270.         comments['goodComments'] = []
  271.         comments['geneComments'] = []
  272.         comments['badComments'] = []

  273.         # 好评
  274.         for i in range(100):
  275.             commentJson = self.getCommJson(item_id, i,score=3)
  276.             if commentJson == None:
  277.                 continue
  278.             if len(commentJson['comments']) == 0:   
  279.                 break
  280.             comments['goodComments'].extend(self.splitComments(commentJson))

  281.         time.sleep(1)
  282.         # 中评
  283.         for i in range(100):
  284.             commentJson = self.getCommJson(item_id, i,score=2)
  285.             if commentJson == None:
  286.                 continue
  287.             if len(commentJson['comments']) == 0:   
  288.                 break
  289.             comments['geneComments'].extend(self.splitComments(commentJson))
  290.         time.sleep(1)
  291.         # 差评
  292.         for i in range(100):
  293.             commentJson = self.getCommJson(item_id, i,score=1)
  294.             if commentJson == None:
  295.                 continue
  296.             if len(commentJson['comments']) == 0:   
  297.                 break
  298.             comments['badComments'].extend(self.splitComments(commentJson))
  299.         time.sleep(1)
  300.         return comments


  301.     def splitComments(self,commentJson):
  302.         comments = []
  303.         for comm in commentJson['comments']:
  304.             comment = {}

  305.             comment["cmid"] = str(comm.get('id',""))    # 该评论的id
  306.             comment["guid"] = str(comm.get('guid',"")) # guid是啥?
  307.             comment["content"] = str(comm.get('content',"")).replace(",",",").replace(' ',"").replace('\n',"").strip()
  308.             comment["creationTime"] = str(comm.get('creationTime',""))
  309.             comment["referenceId"] = str(comm.get('referenceId',""))  # 该评论所属的商品
  310.             comment["replyCount"] = str(comm.get('replyCount',""))
  311.             comment["score"] = str(comm.get('score',""))
  312.             comment["nickname"] = str(comm.get('nickname',""))
  313.             comment["productColor"] = str(comm.get('productColor',""))
  314.             comment["productSize"] = str(comm.get('productSize',""))
  315.             comments.append(comment)

  316.         return comments


  317.     def parseProducts(self, product_list):
  318.         """
  319.         product_list是形如 [[p1_sku1_id,p1_sku2_id,p1_sku3_id],[p2_sku1_id,p2_sku2_id,p2_sku3_id,p2_sku4_id]...] 的列表
  320.         其中列表中的一个元素[p1_sku1_id,p1_sku2_id,p1_sku3_id]又是一个列表,表示一个product的 相同配置,不同颜色的sku
  321.         @param product_list:自己手动构建一个满足条件的60个产品的sku的id列表,然后传进来让程序解析
  322.         """
  323.         for products in product_list:
  324.             parent_product_id = products[0]     # 同一个列表里边默认第一个为父
  325.             for item_id in products:
  326.                 try:
  327.                     url = "https://item.jd.com/" + str(item_id) + ".html"   # 产品的url
  328.                     print(url)
  329.                     html = requests.get(url,headers=self.get_user_hearder())
  330.                     soup = BeautifulSoup(html.text)

  331.                     name = soup.find("div",attrs={"class":"J-crumb-br"}).find("div",attrs={"class":"head"}).find('a').text # 品牌                 
  332.                     self.path = name
  333.                     if not os.path.exists(self.path):
  334.                         os.mkdir(self.path)

  335.                     if not os.path.exists(self.path + "/propertys"):    # 用来放propertys
  336.                         os.mkdir(self.path + "/propertys")

  337.                     try:
  338.                         self.item_path = os.path.join(self.path,str(parent_product_id)) # 同一个父的子产品的图片存在同一个文件夹下
  339.                         if not os.path.exists(self.item_path):
  340.                             os.mkdir(self.item_path)


  341.                         params = self.getParams(soup,item_id) # 获取参数并保存,绝对属性
  342.                         commentMetas = self.getCommMeta(item_id) # 获取评价的相对属性
  343.                         comments = self.getComments(item_id) # 获取100页评价
  344.                         images = self.getImages(soup,self.item_path,item_id) # 获取相片并保存,照片

  345.                         if parent_product_id == item_id:    # 父sku的信息,作为主要的信息,其他的作为备份
  346.                             with open('products.csv', 'a') as f:  #
  347.                                 f.write(name+','+str(item_id)+','+params['skuName']+','+ params['price']+','+commentMetas['goodRateShow']+','+commentMetas['poorRateShow']
  348.                                     +','+commentMetas['commentCount']+','+commentMetas['goodCount']+","+commentMetas['generalCount']+','+commentMetas['poorCount'])

  349.                                 for hotTag in list(commentMetas['hotCommentTags']):
  350.                                     f.write(','+hotTag['name']+":"+str(hotTag['count']))

  351.                                 f.write('\n')


  352.                         # 不是父sku则存到其他文件作为备份
  353.                         with open('products_backup.csv', 'a') as f:  #
  354.                             f.write(name+','+str(item_id)+','+params['skuName']+','+ params['price']+','+commentMetas['goodRateShow']+','+commentMetas['poorRateShow']
  355.                                 +','+commentMetas['commentCount']+','+commentMetas['goodCount']+","+commentMetas['generalCount']+','+commentMetas['poorCount'])

  356.                             for hotTag in list(commentMetas['hotCommentTags']):
  357.                                 f.write(','+hotTag['name']+":"+str(hotTag['count']))
  358.                             f.write('\n')

  359.                         with open(name+'/propertys/' + str(item_id)+'_propertys.csv','w') as f:
  360.                             for key in params['paramsList'].keys():
  361.                                 f.write(key+','+params['paramsList'][key]+'\n')

  362.                         with open(name+'/' + str(parent_product_id)+'_comments.csv','a') as f:
  363.                             try:
  364.                                 # 存好评
  365.                                 for comm in comments['goodComments']:
  366.                                     try:
  367.                                         f.write(str(comm['cmid'])+','+str(comm['guid'])+','+comm['nickname']+','+comm['score']+','+'good,'+comm['creationTime']+','+comm['content'])
  368.                                     except Exception as e:
  369.                                         print("exception: " + str(e))
  370.                                     if 'commentTags' in comm.keys():
  371.                                         for commentTag in comm['commentTags']:
  372.                                             f.write(','+commentTag['name'])
  373.                                     f.write('\n')   

  374.                             except:
  375.                                 print('comment error save good comm' + str(item_id))
  376.                                 traceback.print_exc()
  377.                             try:
  378.                                 # 存中评
  379.                                 for comm in comments['geneComments']:
  380.                                     try:
  381.                                         f.write(str(comm['cmid'])+','+str(comm['guid'])+','+comm['nickname']+','+comm['score']+','+'gene,'+comm['creationTime']+','+comm['content'])
  382.                                     except Exception as e:
  383.                                         print("exception: " + str(e))
  384.                                     if 'commentTags' in comm.keys():
  385.                                         for commentTag in comm['commentTags']:
  386.                                             f.write(','+commentTag['name'])
  387.                                     f.write('\n')
  388.                             except:
  389.                                 print('comment error save gene comm' + str(item_id))
  390.                             try:
  391.                                 # 存差评
  392.                                 for comm in comments['badComments']:
  393.                                     try:
  394.                                         f.write(str(comm['cmid'])+','+str(comm['guid'])+','+comm['nickname']+','+comm['score']+','+'bad,'+comm['creationTime']+','+comm['content'])
  395.                                     except Exception as e:
  396.                                         print("exception: " + str(e))
  397.                                     if 'commentTags' in comm.keys():
  398.                                         for commentTag in comm['commentTags']:
  399.                                             f.write(','+commentTag['name'])
  400.                                     f.write('\n')   

  401.                             except:
  402.                                 print('comment error save bad comm' + str(item_id))                 
  403.                     except Exception as e:
  404.                         # 每个商品,解析错误的时候,记录日志
  405.                         with open('item_exception.log','a') as f:
  406.                             # 格式:当前时间,所属类别,产品id,错误原因
  407.                             log = str(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ","+self.path + ","+ str(item_id) + ","+str(e)+"\n"
  408.                             f.write(log)
  409.                         traceback.print_exc()

  410.                     time.sleep(2)   # 休息2秒
  411.                 except Exception as e:
  412.                     with open('item_error.log','a') as f:
  413.                         # 格式:当前时间,所属类别,产品id,错误原因
  414.                         log = str(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ","+ str(item_id) +str(e)+"\n"
  415.                         f.write(log)
  416.                         print(log)

  417.             # break


  418.     def split_comment_csv(self):
  419.         """
  420.         遍历所有评论文件,(即以_comments.csv结尾的文件),根据标点符号分句
  421.         """
  422.         file_list = []
  423.         dirs = os.listdir(".")
  424.         for dir_name in dirs:
  425.             if os.path.isdir(dir_name):
  426.                 for name in os.listdir(dir_name):
  427.                     if os.path.isfile(dir_name+"/"+name):
  428.                         item = {}
  429.                         item["filePath"] = dir_name+"/"+name
  430.                         item['fileName'] = name
  431.                         item['dirName'] = dir_name
  432.                         file_list.append(item)

  433.         if not os.path.exists('comment_clause'):
  434.             os.mkdir('comment_clause')

  435.         for item in file_list:
  436.             reader = csv.reader(open(item['filePath']))
  437.             csv_writer_name = 'comment_clause/' + item['dirName'] +"_" + item['fileName']

  438.             with open(csv_writer_name, 'w', newline='\n') as csvfile:
  439.                 for row in reader:
  440.                     if len(row) >= 7:
  441.                         clauses = re.split(',|。|?|!|;|;|、|\?|!|·|)|(',row[6])

  442.                         for clause in clauses:
  443.                             clause.replace('&hellip','')
  444.                             clause = clause.strip()
  445.                             if len(clause) != 0:
  446.                                 csvfile.write(clause+"\n")


  447.     def count_origin_comments(self):
  448.         """
  449.         对原始的未断句之前的评论统计数量
  450.         """
  451.         file_list = []
  452.         dirs = os.listdir(".")
  453.         for dir_name in dirs:
  454.             if os.path.isdir(dir_name):
  455.                 for name in os.listdir(dir_name):
  456.                     if os.path.isfile(dir_name+"/"+name):
  457.                         item = {}
  458.                         item["filePath"] = dir_name+"/"+name
  459.                         item['fileName'] = name
  460.                         item['dirName'] = dir_name
  461.                         file_list.append(item)

  462.         countData = []
  463.         totalRowNum = 0 # 评论总条数
  464.         totalClauseNum = 0  # 断句后的句子总数
  465.         for item in file_list:
  466.             reader = csv.reader(open(item['filePath']))
  467.             rowNum = 0  # 该文件中的行数
  468.             clauseNum = 0
  469.             for row in reader:
  470.                 if len(row) >= 7:
  471.                     rowNum = rowNum + 1
  472.                     clauses = re.split(',|。|?|!|;|;|、|\?|!|·|)|(',row[6])

  473.                     for clause in clauses:
  474.                         clause.replace('&hellip','')
  475.                         clause = clause.strip()
  476.                         if len(clause) != 0:
  477.                             clauseNum = clauseNum + 1   

  478.             totalClauseNum = totalClauseNum + clauseNum
  479.             totalRowNum = totalRowNum + rowNum
  480.             data_item = {}
  481.             data_item['fileName'] = item['fileName']
  482.             data_item['clauseNum'] = str(clauseNum)
  483.             data_item['rowNum'] = str(rowNum)
  484.             countData.append(data_item)

  485.         with open('countData.csv', 'w') as f:
  486.             f.write('文件名,原始评论条数,断句条数\n')
  487.             for item in countData:
  488.                 f.write(item['fileName']+","+item['rowNum']+","+item['clauseNum']+'\n')
  489.             f.write('评论总数,'+ str(totalRowNum)+"\n")
  490.             f.write('句子总数,'+ str(totalClauseNum)+"\n")


  491. # -----------------------测试---------------------------

  492.     def test_get_all_brand_url(self):
  493.         text = json.loads(requests.get(self.url,headers=self.get_user_hearder()).text)

  494.         for brand in text['brands']:
  495.             url = 'https://list.jd.com/list.html?cat=9987,653,655&ev=exbrand_' + str(brand['id'])+'&sort=sort_rank_asc&trans=1&JL=3_'+quote(brand['name'])
  496.             print(url)


  497.     def test_find_next_page(self,url):
  498.         soup = BeautifulSoup(requests.get(url,headers=self.get_user_hearder()).text)
  499.         href = soup.find("a",attrs={"class":"pn-next"}) # 下一页


  500.         if href:
  501.             print(href.get('href'))
  502.             brand_url = 'https://list.jd.com'+href.get('href')
  503.         else:
  504.             brand_url = ''
  505.             print('url is None')
  506.         print(brand_url)


  507.     def test_get_comment_json(self,productId):
  508.         json_content = self.getCommJson(productId)
  509.         print(json_content)
  510.         for comm in json_content['comments']:
  511.             print(comm['content'].replace('\n',''))


  512.     def test_read_csv(self):
  513.         reader = csv.reader(open('test.csv'))
  514.         for row in reader:
  515.             if len(row) >= 6:
  516.                 print(row[6] + '\n')

  517. if __name__ == '__main__':
  518.     jingdong = Jingdong()
  519.     # 爬全部的品牌
  520.     # jingdong.parse_brand()
  521.     # 测试
  522.     # jingdong.getCommJson(12280434216,0,0)
  523.     # 测试
  524.     # jingdong.test_get_all_brand_url()
  525.     # jingdong.test_find_next_page('https://list.jd.com/list.html?cat=9987,653,655&ev=exbrand%5F8557&page=3&sort=sort_rank_asc&trans=1&JL=6_0_0')
  526.     # jingdong.test_get_comment_json(11083454031)

  527.     # 爬需要的60个手机型号(现在只有33个型号)

  528.     # product_list = [  
  529.     # [3857525,4669576],[4411638, 4316775,4431603],[3924115,3875973],[3398125],[5097448,4199965],
  530.     #   [4502433,4199967],[4411628],[3857521],[1345368],[11375078958,11774045896,11546640578],
  531.     #   [4461939],[10417752533,10417197477],
  532.     #   [10827008669],[4869176],[4086221,4086223,3867555,3867557],
  533.     #   [4432058,4432056,4432052,4086229,4086227],[3352172,3352168],[4222708,3763103],[4170768,4170788,4170784,4170782],
  534.     #   [4978326,4978306,4978332,5247848],[3729301,3729311,3729315],[10399574837,10416687137,10437750952,11089374104,11089374105],
  535.     #   [1816276356,1816276354,10256482570,1816276355],[10065260353,10065260354,10069410228,10069410229],
  536.     #   [10654370492,11022002650,10654370493,10654370494],[12481158400,12481163501,13304714040],
  537.     #   [2166504],[3548595,3548599,3979666,3979664],[4363831,4363833,4363805,4363811,4363847],
  538.     #   [4230493,5158518,5158508],[2589814,2589808,2589818],[2972184,2972174,2972172,2972186],[10213303571,10213303572]
  539.     # ]

  540.     # 追加的酷派,努比亚,一加
  541.     product_list = [
  542.         [3397564,3075827,3785780],[3151585,3159473],[3159465],[3789933],[3697279],[2917215],
  543.         [2214850],[4066471],[2401116],[5019352,4160791],[10072766014],[10717616871],
  544.         [4345197],[4345173],[5014204,4229972,4161762,2943569],[4746242,4983290,4024777,4746262,4245285],
  545.         [4899658,4996220,4100837,5239536],[4220709,4534743,4220711,4497841],[3139087,3569552],
  546.         [11881030122,11881076398,11839878990,12627332950]
  547.     ]


  548.     jingdong.parseProducts(product_list)

  549.     # jingdong.test_read_csv()

  550.     # jingdong.split_comment_csv()


  551.     # jingdong.count_origin_comments()
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-3-29 05:27

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表