Scrapy练习——爬取京东商城商品信息
刚刚接触爬虫,花了一段时间研究了一下如何使用scrapy,写了一个比较简单的小程序,主要用于爬取京东商城有关进口牛奶页面的商品信息,包括商品的名称,价格,店铺名称,链接,以及评价的一些信息等。简单记录一下我的心得和体会,刚刚入门,可能理解的不够深入不够抽象,很多东西也只是知其然不知其所以然,理解的还是比较浅显,希望有看见的大佬能一起交流。
先上我主要参考的几篇博客,我的爬虫基本上是在这两篇博客的基础上完成的,感谢大佬的无私分享:
小白进阶之Scrapy第一篇
scrapy爬取京东商城某一类商品的信息和评论(一)
首先说明一下我的程序是基于以上二篇博客的基础上进行修改的,主要的改动是针对3.6版本的python,修改了一些已经删除的函数,修改了一些已经更新的页面的网址,还有有些商品是京东全球购,商品页面的信息和京东自营的不一样,对此进行了判定和处理等,并将信息输出到Mysql中。
整个爬虫我已上传至Github,欢迎大家讨论交流。
JDSpider
scrapy爬虫主要可以分为几部分,如下图所示:
有关Scrapy的基本结构在第一篇博客里也有所简单说明,在此不再赘述,如果需要了解更多还是需要看官方文档。在这里我简单说一下我认为比较重要的几个部分。
Spider:这个部分可以认为是爬虫的本体了,他的主要作用就是从下载好的内容中爬到你需要的东西,所以你在写爬虫的时候基本都是对Spider进行修改。
Item Pipeline:这个模块简单的说就是将你爬到的信息进行处理,输出到Mysql等。因此在这里需要完成python到Mysql的输出。
在上面两篇博客的基础上对代码进行了一定的修改,我的编程环境是Python 3.6,开发环境是win10下的Pycharm。需要注意的一点是,在IDE中进行爬虫的运行和调试需要添加一些内容,如果是在IDE下进行运行的话,需要在项目的根目录下添加一个名为entrypoint的py文件,其中的代码如下:
from scrapy.cmdline import execute execute(['scrapy','crawl','JDSpider']) #用于在IDE里运行
其中JDSpider即是你自定义的Spider的name属性,注意一定要与Spider的名字匹配。
如果要在IDE下进行调试的话,则需要在与setting.py的目录下添加一个名为run.py的文件,文件的代码如下:
# -*- coding: utf-8 -*- from scrapy import cmdline name = 'JDSpider' cmd = 'scrapy crawl {0}'.format(name) cmdline.execute(cmd.split()) #用于在IDE里进行Debug
需要运行爬虫的时候,直接运行entrypoiot.py即可,同理,进行调试的时候debug entrypoint.py。
下面开始进行爬虫的编写了。第一步,先确定你需要进行爬取的信息都有那些,那么我们先来编写items.py。代码如下:
import scrapyclass JDSpiderItem(scrapy.Item):# define the fields for your item here like:ID = scrapy.Field() # 商品IDname = scrapy.Field() # 商品名字comment = scrapy.Field() # 评论人数shop_name = scrapy.Field() # 店家名字price = scrapy.Field() # 价钱link = scrapy.Field()comment_num = scrapy.Field()score1count = scrapy.Field() # 评分为1星的人数score2count = scrapy.Field() # 评分为2星的人数score3count = scrapy.Field() # 评分为3星的人数score4count = scrapy.Field() # 评分为4星的人数score5count = scrapy.Field()
这一部分比较简单,只要将你想要爬取的信息提供一个Scrapy.Field()方法即可。
第二部分的内容是编写爬虫的设置,修改settings.py中的代码。
MYSQL_HOSTS = "127.0.0.1" MYSQL_USER = "root" MYSQL_PASSWORD = "7911upup" MYSQL_PORT = 3306 MYSQL_DB = "JD_test"# HTTPCACHE_ENABLED = True # HTTPCACHE_EXPIRATION_SECS = 0 # HTTPCACHE_DIR = 'httpcache' # HTTPCACHE_IGNORE_HTTP_CODES = [] # HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'# DOWNLOAD_DELAY = 7 # 下载延迟
其中第一部分的内容是有关Mysql的接口,127.0.0.1是本机的保留地址,root是Mysql数据库的账户名称,第三行是密码,第四行是端口,默认为3306,第五行是mysql建立的database名称。
第二部分是本地缓存,如果取消注释的话是建立本地缓存,这样能够减少网站压力,也方便进行调试,我一开始在调试的过程中是保留本地缓存的,但是在进行调试的过程中发现经过一段时间的调试之后发生了数据丢失的现象,不知道是不是跟我的程序编写有关系,所以我个人建议如果是刚开始进行调试的时候尽可能的减少爬取的数据量,并不使用本地的缓存,这样能够防止数据出现错误,便与调试。
既然刚才提到了Mysql,这里也简单说一下mysql的操作吧,由于我对这一块不太了解,在这里也不献丑了,直接上代码,看代码还是比较好理解的,就是首先建立一个database,然后在其中建立一个table,然后再设置一些变量的名称和类型。
#create database JD_test character set gbk; use JD_test; DROP TABLE IF EXISTS `JD_name`; CREATE TABLE `JD_name` (`id` int(11) NOT NULL AUTO_INCREMENT,`good_id` varchar(255) DEFAULT NULL,`name` varchar(255) DEFAULT NULL,`price` varchar(255) DEFAULT NULL,`comment` varchar(255) DEFAULT NULL,`shop_name` varchar(255) DEFAULT NULL,`link` varchar(255) DEFAULT NULL,`score1count` varchar(255) DEFAULT NULL,`score2count` varchar(255) DEFAULT NULL,`score3count` varchar(255) DEFAULT NULL,`score4count` varchar(255) DEFAULT NULL,`score5count` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8mb4; truncate JD_name;
至于python这一部分,在3.6中是用到了pymysql这个库完成二者的连接的。这一部分的代码如下。
import pymysql.connections import pymysql.cursors MYSQL_HOSTS = "127.0.0.1" MYSQL_USER = "root" MYSQL_PASSWORD = "7911upup" MYSQL_PORT = 3306 MYSQL_DB = "JD_test"connect = pymysql.Connect(host = MYSQL_HOSTS,port = MYSQL_PORT,user = MYSQL_USER,passwd = MYSQL_PASSWORD,database = MYSQL_DB,charset="utf8" )cursor = connect.cursor() # # 插入数据 class Sql:@classmethoddef insert_JD_name(cls,id, name, shop_name, price, link,comment_num ,score1count, score2count, score3count, score4count, score5count):sql = "INSERT INTO jd_name (good_id, name, comment, shop_name, price, link ,score1count, score2count," \" score3count, score4count, score5count) VALUES ( %(id)s, %(name)s, %(comment_num)s, %(shop_name)s, %(price)s" \", %(link)s, %(score1count)s, %(score2count)s, %(score3count)s, %(score4count)s, %(score5count)s )"value = {'id' : id,'name' : name,'comment' : comment_num,'shop_name' : shop_name,'price' : price,'link' : link,'comment_num' : comment_num,'score1count' : score1count,'score2count' : score2count,'score3count' : score3count,'score4count' : score4count,'score5count' : score5count,}cursor.execute(sql, value)connect.commit()
接下来就是Spider的编写了,在Spider类中有几个比较重要的变量和函数,一个是start_url,这个是爬虫开始爬取的网站地址,由于在JD首页进行搜索显示的页面是30条动态加载的,所以爬取不是特别方便,所以选取在首页左侧中的进口牛奶分类的页面,该页面能够直接显示60条商品数据。网址为https://list.jd.com/list.html?cat=1320,5019,12215&page=N&sort=sort_totalsales15_desc&trans=1&JL=6_0_0#J_main。这里N即为具体的页码,通过如下代码将start_url设置成为一个list。
start_urls = []for i in range(1, 10+1): # 这里需要自己设置页数url = 'https://list.jd.com/list.html?cat=1320,5019,12215&page='+ str(i)+'&sort=sort_totalsales15_desc&trans=1&JL=6_0_0#J_main'start_urls.append(url)
第二个比较重要的函数是parse,在这里我们素质四连,一共有parse,parse_detail,parse_getCommentnum,parse_price四个方法,parse用来爬取商品的ID,链接,还有商品的名称;parse_detail用来爬取商品的店铺名,后面两个方法则是用来爬取评论数和不同评价的人数以及商品的价格。
解析数据的话,可以用Xpath直接解析,也可以用导入的BS4等库来做,在这里我用Xpath+正则表达式的一套combo来完成,不懂的老哥可以先看一下这个有关正则表达式的介绍。相比于我参考的代码,在网站解析这一部分很多解析的代码已经失效了,年久失修只能我自己动手来修改,刚开始上手确实有点麻烦,毕竟没有JS基础,看网页源代码有些吃力,后来操作了一番以后也就有点熟悉了,简单介绍一下如何查找你需要的元素。
我采用的是猎豹浏览器,是基于Chrome内核的,调试起来应该跟Chrome没什么区别,首先在对应的页面单击F12,出现如下页面:
首先进行观察,可以看出所有的商品都有一个class=‘gl-item’的标签,再单击所示图标,将光标移动到你需要的信息上点右键,例如某一个商品的名称哪里,即可在右边显示出对应的信息,从图中可以知道这个商品名称的信息是在 li//div/div[@class="p-name"]/a/em/ 的text中,同时也可以看出其中的文本还包括一些空格等等,所以需要使用正则表达式对其进行筛选。这里的代码如下:
def parse(self, response): # 解析搜索页# print(response.text)sel = Selector(response) # Xpath选择器goods = sel.xpath('//li[@class="gl-item"]')for good in goods:item1 = JDSpiderItem()temp1 = str(good.xpath('./div/div[@class="p-name"]/a/em/text()').extract())pattern = re.compile("[\u4e00-\u9fa5]+.+\w") #从第一个汉字起 匹配商品名称good_name = re.search(pattern,temp1)item1['name'] = good_name.group()item1['link'] = "http:" + str(good.xpath('./div/div[@class="p-img"]/a/@href').extract())[2:-2]item1['ID'] = good.xpath('./div/@data-sku').extract()if good.xpath('./div/div[@class="p-name"]/a/em/span/text()').extract() == ['全球购']:item1['link'] = 'https://item.jd.hk/' + item1['ID'][0] +'.html'url = item1['link'] + "#comments-list"yield scrapy.Request(url, meta={'item': item1}, callback=self.parse_detail)
简单的说一下几个需要注意的地方,一个是正则表达式中,[\u4e00-\u9fa5]+从第一个汉字开始匹配,这里其实是有一点小BUG的,因为有的商品名称是以字符和数字或者标点符号开头的,由于我爬取的商品信息第一页里没有这种情况,所以我也没有修改,后面应该进行适当的调整,修改一下这个正则表达式。第二个是注意re模块中search和match的区别,match是从第一个字符开始进行匹配,而search是在整个字符串中进行匹配,建议使用search。第三个需要注意的地方是对于牛奶这种商品,分为两个类型,一个是JD自营的或者第三方的一些店铺,这些网址是类似的,而还有一种是京东全球购,这种商品的网址跟之前的是不一样的,网址开头是items.jd.hk。因此在爬的过程中要将全球购的这个标签给选取出来,针对不同的商品类型,对link的值进行修改,这样传递给request才是有效的url。
parse_detail这个函数是用于爬取商品的店铺名的,这里进入了商品的详情页面,url是通过parse函数抓取的ID生成的,全球购和国内商品的url不同,在这里对于店铺的抓取也是不同的,其中的标签是不一样的,需要注意的就是有的商品是京东自营的,没有具体的店铺名,在这里需要进行判别。
def parse_detail(self, response):# passitem1 = response.meta['item']sel = Selector(response) # Xpath选择器if response.url[:18] == 'https://item.jd.hk': #判断是否为全球购goods = sel.xpath('//div[@class="shopName"]')temp = str(goods.xpath('./strong/span/a/text()').extract())[2:-2]if temp == '':item1['shop_name'] = '全球购:'+ 'JD全球购' #判断是否JD自营else:item1['shop_name'] = '全球购:' + temp# print('全球购:'+ item1['shop_name'])else:goods = sel.xpath('//div[@class="J-hove-wrap EDropdown fr"]')item1['shop_name'] = str(goods.xpath('./div/div[@class="name"]/a/text()').extract())[2:-2]if item1['shop_name'] == '': #是否JD自营item1['shop_name'] = '京东自营'# print(item1['shop_name'])
下面的两个parse函数没有太多的改动,与第二篇博客中的相差无几,只是把其中解析的网址做了替换,之前的不能用了。在此也不多说了,烦请各位移步那篇博客。我就只上个代码了。
def parse_price(self, response):item1 = response.meta['item']temp1 = str(response.body).split('jQuery712392([')s = temp1[1][:-6] # 获取到需要的json内容js = json.loads(str(s)) # js是一个listitem1['price'] = js['p']return item1def parse_getCommentnum(self, response):item1 = response.meta['item']js = json.loads(str(response.body)[2:-1])item1['score1count'] = js['CommentsCount'][0]['Score1Count']item1['score2count'] = js['CommentsCount'][0]['Score2Count']item1['score3count'] = js['CommentsCount'][0]['Score3Count']item1['score4count'] = js['CommentsCount'][0]['Score4Count']item1['score5count'] = js['CommentsCount'][0]['Score5Count']item1['comment_num'] = js['CommentsCount'][0]['CommentCount']num = item1['ID'] # 获得商品IDs1 = re.findall("\d+",str(num))[0]url = "http://p.3.cn/prices/mgets?callback=jQuery712392&type=1&area=1_2800_2849_0.138365810&pdtk=&pduid=15083882680322055841740&pdpin=jd_4fbc182f7d0c0&pin=jd_4fbc182f7d0c0&pdbp=0&skuIds=J_" + s1yield scrapy.Request(url, meta={'item': item1}, callback=self.parse_price)
最后的部分就是pipeline,这里完成对爬取的数据的输出,输出到mysql中。
class JdspiderPipeline(object):def process_item(self, item, spider):if isinstance(item, JDSpiderItem):good_id = item['ID']good_name = item['name']shop_name = item['shop_name']price = item['price']link = item['link']comment_num = item['comment_num']score1count = item['score1count']score2count = item['score2count']score3count = item['score3count']score4count = item['score4count']score5count = item['score5count']Sql.insert_JD_name(good_id, good_name, shop_name, price, link,comment_num ,score1count, score2count, score3count, score4count, score5count)# print('存储一条信息完毕了哦')return item
在Mysql输出到csv中时会出现一个问题,即输出的中文会出现乱码,在这里提供一个解决方案,将输出的csv文件以记事本的形式打开,另存为csv的时候可以选择以utf-8进行存储,然后再打开即可。
成品图如下:
以上就是我关于Scrapy模块编写爬虫时的一些心得了, 仓促完成的一篇博客,多有疏漏,自己理解不深的地方还有很多,继续加油。
转载于:https://www.cnblogs.com/fengf1/p/7905013.html
Scrapy练习——爬取京东商城商品信息相关推荐
- python爬取京东手机参数_python爬虫——分页爬取京东商城商品信息(手机为例)...
1.最近刚开始学习python 写了个爬虫练习,感觉主要是得会用F12查询网站结构代码.还涉及到反爬虫,每个网站都不一样,拿到的解析出的json数据格式也不同.得有些Web知识的基础才行. htt ...
- scrapy框架爬取京东商城商品的评论
一.Scrapy介绍 Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中. 所谓网络爬虫,就是一个在网上到处或定向抓取 ...
- Python爬虫教程:Python爬取京东商城商品大图详解
Python爬取京东商城商品大图详解 做为一个爬虫初学者,在做爬取网址图片的练习中以京东网为例爬取商品大图并保存在相应的文件夹 1.导入模块 import urllib.request import ...
- 爬虫利器Pyppeteer的介绍和使用 爬取京东商城书籍信息
提起 selenium 想必大家都不陌生,作为一款知名的 Web 自动化测试框架,selenium 支持多款主流浏览器,提供了功能丰富的API 接口,经常被我们用作爬虫工具来使用.但是 seleniu ...
- 爬虫利器Pyppeteer的介绍和使用 爬取京东商城书籍信息!
提起 selenium 想必大家都不陌生,作为一款知名的 Web 自动化测试框架,selenium 支持多款主流浏览器,提供了功能丰富的API 接口,经常被我们用作爬虫工具来使用.但是 seleniu ...
- 利用python爬虫爬取京东商城商品图片
笔者曾经用python第三方库requests来爬取京东商城的商品页内容,经过解析之后发现只爬到了商品页一半的图片.(这篇文章我们以爬取智能手机图片为例) 当鼠标没有向下滑时,此时查看源代码的话,就会 ...
- python+scrapy简单爬取淘宝商品信息
python结合scrapy爬取淘宝商品信息 一.功能说明: 已实现功能: 通过scrapy接入selenium获取淘宝关键字搜索内容下的商品信息. 待扩展功能: 爬取商品中的全部其他商品信息. 二. ...
- 基于python和selenium爬取JD商城商品信息并且分析用户对于产品的满意程度
我把整个代码都托管在github上了,那里面有详细的api说明文档 https://github.com/hao297531173/JDCommentSpider/tree/master PS:获取的 ...
- 爬取京东图书商品信息
关键之处在于页面上的评论数的信息是动态加载的,是通过那个标签唯一的id号进行url拼接获得一个json文件然后显示的评论数. 抓包寻找了许久之后发现了一个奇特的文件. 然后再源代码里面搜索发现这个是商 ...
最新文章
- mysql 系统表 存储过程_数据库系统(六)---MySQL语句及存储过程
- rhino5.0安装教程
- javaWeb服务详解【客户端调用】(含源代码,测试通过,注释) ——applicationContext.xml
- leetcode474. 一和零(动态规划)
- NIPS’20 Spotlight | 精准建模用户兴趣,广告CTR预估准确率大幅提升!
- Pytest参数选项自由执行测试用例详解(二)
- cadence 16.6中Z-copy的用法
- 杭电OJ分类题目(4)-Graph
- 买车,给点建议和意见
- 数据库 之 Mysql的表分区
- c语言cyc函数,cyc指标源码
- 【Crystal Reports 水晶报表】奇偶行显示不同的颜色 另附CrystalReports常用属性
- R-S编码译码-缩短码(10,6)
- 计算机网络实验一(常见服务和静态IP设置)
- php文章下一页,php实现文章上一页下一页的实例
- mipi的dsi全称_MIPI DSI 协议介绍
- 在Centos7下捣鼓邮件发送软件sendmail与postfix
- 招行首发芭比娃娃MP3
- 提示BeanPostProcessorChecker:is not eligible for getting processed by all BeanPostProcessors的原因
- 没有鼠标就无法对计算机进行操作,电脑鼠标不灵敏是什么原因?怎么解决?
热门文章
- Pycharm如何关掉jupyter notebook server
- Python Setuptools 升级(Upgrade)
- urllib使用cookies(下载,提取)
- java scriptrunner_ScriptRunner.java
- 防盗链测试01 - Jwplayer+Tengine2.3.1 mp4模块打造流媒体测试服务器
- 详解python正则\b和\B的区别
- Vue使用better-scroll左右菜单联动
- 记录一些精品开源项目
- 初识Django —Python API接口编程入门
- j2ee爬坑行之一:web容器