张政的技术专栏 A Coder

京东商品详细数据爬取

2018-05-21

阅读:


最近做了一个公司的homework。题目如下: 题目:用任意程序实现,抓取京东在售的三星手机的信息 信息包括:手机名称,价格,运行内存,电池容量,机身颜色,摄像头像素

重点是python正则表达式的写法,这里有个正则表达式课程,很好很全面。

在网上找了个 参考代码,但是有些地方需要更改

不多说,直接贴代码:

		# coding=utf-8

		#导入模块
		import re
		from bs4 import BeautifulSoup
		import json,time
		import urllib


		#定义抓取类
		class JD:

			#记录抓取产品个数
			prodNum = 1
			#初始化参数
			def __init__(self,baseurl,page):
				self.baseurl = baseurl
				self.page = page
				#拼装成url
				self.url = self.baseurl+'&'+'page='+str(self.page)
			#获取html源代码
			def getHtml(self,url):
				#请求抓取对象
				request = urllib.request.Request(url)
				#响应对象
				reponse = urllib.request.urlopen(request)
				#读取源代码
				html = reponse.read()
				#返回源代码
				return html
			#获取总页数
			def getNum(self,html):
				#封装成BeautifulSoup对象
				soup = BeautifulSoup(html)
				#定位到总页数节点
				items = soup.find_all('span',class_='p-skip')
				#获取总页数
				for item in items:
					pagenum = item.find('em').find('b').string
				return pagenum
			#获取所有产品id列表
			def getIds(self,html):
				#生成匹配规则
				pattern =  re.compile('<a target="_blank" href="//item.jd.com/(.*?).html".*?>')
				#查询匹配对象
				html = html.decode('utf-8')  # python3
				items = re.findall(pattern,html)
				return items
			#根据产品id获取同款产品列表
			def getIdByItems(self,id):
				#拼装成url
				url = basePd+str(id)+'.html'
				#调用抓取函数返回源代码
				#print(url)
				html = self.getHtml(url)
				# 封装成BeautifulSoup对象
				soup = BeautifulSoup(html)
				#查询匹配对象
				#print(soup)
				items = soup.find('div',id='choose-attrs')#plist#plist//*[@id="plist"]
				#soup2 = BeautifulSoup(items)
				#items = soup2.find('',)
				#print(items)
				l = []
				#生成列表
				for item in items:
					print(item)
					pattern = re.compile(r'data-sku="(.+?)"')
					#print(pattern)
					id = re.findall(pattern,str(item))
					print(id)

					if id:
						l += id

				return l

			#获取产品价格
			def getPrice(self,id):
				url = 'http://p.3.cn/prices/mgets?skuIds=J_'+str(id)
				jsonString = self.getHtml(url)
				jsonObject = json.loads(jsonString.decode())
				price_jd = jsonObject[0]['p']
				price_mk = jsonObject[0]['m']
				print ('京东价格:',str(price_jd),file=f)
				print ('市场价格:',str(price_mk),file=f)

			# def getImg(self,html,subid):
			#     pattern = re.compile(r'<img id=.*?data-origin="(.*?)" alt=.*?', re.S)
			#     items = re.findall(pattern, html)
			#     for item in items:
			#         imgurl = 'http:%s' % (item)
			#         urllib.request.urlretrieve(imgurl, 'd:/temp/jdimg/%s.jpg' % (str(subid)))

			#获取内容
			def getContent(self,html,subid):
				soup = BeautifulSoup(html)
				title = soup.find('div',class_='sku-name')
				print ('\n-----------------第'+ str(JD.prodNum) +'个产品--------------------\n',file=f)
				for t in title:
					print ('名称: ',t.string,file=f)
				time.sleep(1)
				#价格
				self.getPrice(subid)
				#编码
				print ('产品编码:%s' % (str(subid)),file=f)
				items1 = soup.find_all('ul',class_='parameter1 p-parameter-list')
				#商品基本信息
				for item in items1:
					p = item.findAll('p')
					for i in p:
						print (i.string,file=f)
				# 商品基本信息
				items2 = soup.find_all('ul', class_='parameter2 p-parameter-list')
				for item in items2:
					p = item.findAll('li')
					for i in p:
						print (i.string,file=f)
				#规格与包装

				items3 = soup.select('div.ETab>div.tab-con>div>table>tbody>tr ')
				<font color="#dd0000">#在我们想要抓取的目标当中,出现了两个完全不同的类型,一个是普通的手机,一个是全球购的手机,两个网页构成完全不同了,也就造成了一个pattern不能匹配到所有的数据,我们使用了if else方式来解决这个问题</font><br /> 
				print(items3)
				if items3 :
					for item in items3:
						for d in item.find_all('td'):
							print(d,file=f)

				else:
					items3 = soup.find_all('div', class_='Ptable-item')
					for item in items3:
						contents1 = item.findAll('dt')
						contents2 = item.findAll('dd')
						for i in range(len(contents1)):
							print( contents1[i].string,contents2[i].string,file=f)
				JD.prodNum += 1

			#启动抓取程序
			def start(self):
				html = spider.getHtml(self.url)
				pageNum = self.getNum(html)
				print ('正在抓取网页请稍后............')
				time.sleep(3)
				print( '抓取完毕,本次共抓取',pageNum,'页。')
				time.sleep(1)
				print( '正在解析内容.........')
				#循环1--页数
				for page in range(1,int(pageNum)+1):
					url = self.baseurl+'&'+'page='+str(page)
					html = self.getHtml(url)
					ids = self.getIds(html)
					#循环2--产品列表
					for id in ids:
						urlprod = basePd+str(id)+'.html'
						#htmlprod = self.getHtml(urlprod)
						subids = self.getIdByItems(id)
						#循环3--产品组列表
						for subid in subids:
							urlsubprod = basePd+str(subid)+'.html'
							subhtml = self.getHtml(urlsubprod)
							time.sleep(1)
							self.getContent(subhtml,subid)
							#self.getImg(subhtml,subid)

		#产品列表base页
		basePd  = 'http://item.jd.com/'
		#抓取入口URL
		baseURL = 'https://search.jd.hk/Search?keyword=%E6%89%8B%E6%9C%BA&enc=utf-8'#'http://list.jd.com/list.html?cat=9987,653,655&ev=exbrand_15127&sort=sort_rank_asc&trans=1&JL=3_%E5%93%81%E7%89%8C_%E4%B8%89%E6%98%9F%EF%BC%88SAMSUNG%EF%BC%89#J_crumbsBar'#'http://list.jd.com/list.html?cat=9987,653,655'
		#生成爬虫抓取对象
		spider = JD(baseURL,1)
		f = open("JD02.json", 'w+',encoding='utf-8')
		#开始抓取
		spider.start()

抓取到的是京东商品的全部的详细参数,并不是我们所要求的那几个种类,接下来就是筛选我们想要的信息了,我仍然用的正则匹配来做。 其中不同的,部分代码如下(配合notepad++的替换功能,完全可以实现的。):

		# _*_coding:utf-8_*_
		import re
		import sys
		import json
		import numpy as np
		k = open("JD-p.json", 'w+',encoding='utf-8')
		f = open('JD03.json', 'r', encoding='UTF-8')#导入已经准备好的所有数据

		_list = [[0 for col in range(8)] for row in range(3320)]

		for line in f.readlines():#按行处理,之前已经把每一组数据处理为一行了(notepad++)
			pattern = re.findall(r"商品名称:(.+)商品编号", line)
			pattern2 = re.findall(r"京东价格:(.+)市场价格:", line)
			pattern3 = re.findall(r"市场价格:(.+)产品编码:", line)
			pattern4 = re.findall(r"电池容量\(mAh\)(.+)电池类型", line)
			if not pattern4:
				pattern4 = re.findall(r"电池容量\(mAh\)(.+)电池是否可拆卸", line)
			pattern5 = re.findall(r"颜色:(..)系", line)
			if not pattern5:
				pattern5 = re.findall(r"机身颜色 (.+)机身长度", line)
			pattern6 = re.findall(r"前置摄像头 (.+) 前摄光圈大小", line)
			pattern7 = re.findall(r"后置摄像头:(.+) 前置摄像头:", line)
			pattern8 = re.findall(r"运行内存:(...)", line)

			if pattern :
				print(pattern,pattern2,pattern3,pattern4,pattern5,pattern6,pattern7,pattern8,file = k)#

最后我想把得到的数据按照xlsx格式
提交,就把JD-p完全复制粘贴到一个空白xlsx文件。 然后选中第一列-> 数据->分列->分隔符号(][我使用的是两个紧挨着的中括号) 搞定。

其实其中出现了很多问题,比如说我们在使用原博主程序直接跑的时候,会报错。


Comments

Content