最近做了一个公司的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文件。
然后选中第一列-> 数据->分列->分隔符号(][我使用的是两个紧挨着的中括号)
搞定。
其实其中出现了很多问题,比如说我们在使用原博主程序直接跑的时候,会报错。