基于Scrapy的爬虫爬取京东商品信息与评论

来源:互联网 发布:淘宝试用规则 编辑:程序博客网 时间:2024/05/21 00:18
总体概述

从京东搜索框搜索进入手机进入页面,爬取内容分成两类,一类是手机的基本信息(标题、价格、链接),另一类是评论信息(用户名、评论内容、评论总数等),将信息爬取下来之后,进行数据处理,以方便显示和查看的格式保存下来。

(1)爬虫
爬虫又称网络蜘蛛、网络蚂蚁、网络机器人等,是一种按照一定的规则自动地抓取万维网信息的程序或者脚本,它的原理简单来讲就是通过选定入口URL,模拟HTTP请求,找到页面上想要获取的数据,然后保存下来。
(2)Scrapy框架
Scrapy是Python开发的一个快速、高层次的屏幕抓取和WEB抓取框架,用于抓取web站点并从页面中提取结构化数据。用途比较广泛,可用于数据挖掘、监测和自动化测试。
Scrapy是一个自定义程度很高的框架,任何人都可以根据自己的需求很方便填写或者重写里边的函数。它页提供了多种类型的爬虫基类。
(3)XPath
XPath即为XML路径语言,是一种用来确定文档中某部分位置的语言,XPath基于XML的树状结构,提供在数据结构中寻找节点的能力,也可用于HTML页面。
通过浏览器查看页面源码,找到我们想要的信息的节点位置,然后通过XPath的路径表达式,对节点进行遍历,从而获得数据。

工程文件结构
通过命令行创建一个Scrapy工程文件,文件结构如下图,在这个项目中,主要编写items.py、pipelines.py、setting.py以及sogou.py(爬虫文件)这四个文件。并将手机基本信息储存在mydata.json文件中,评论信息储存在mydata1.json文件中,product_url.txt储存每个商品的链接,这个文件的主要作用是抓取评论时方便读取每个商品额url。




①items.py
因为写了两个爬虫,一个爬取手机信息,一个爬取评论信息,所以我们定义了两个类JdphoneItem和CommentItem

import scrapyclass JdPhoneItem(scrapy.Item):    url = scrapy.Field()    #商品链接    title = scrapy.Field()  #商品标题    price = scrapy.Field()  # 商品价格class CommentItem(scrapy.Item):    user_name = scrapy.Field()  # 用户名    comment_num = scrapy.Field   #评论总数    content = scrapy.Field()  # 评论内容    phone_name = scrapy.Field() #手机名称

②sogou.py
首先,获取入口链接,由于搜索页面的翻页规则是page=1开始,1,3,5,7…..这样以奇数递增,所以用一个循环将前十页加入入口链接。


然后在解析函数里通过XPath表达式爬取信息,并将手机URL单独存一份,方便后续读取。

   得到每个手机的URL之后,从URL中提取商品ID,抓取评论总数,然后求出评论页数,然后构造评论页链接,链接的基本结构是前缀+商品ID+评论页序号+后缀,然后加入到入口链接。然后通过Xpath表达式爬取。


# coding: utf-8import scrapyfrom scrapy_prj.items import JdPhoneItemfrom scrapy_prj.items import CommentItemimport reimport urllib.requestclass PhoneSpider(scrapy.Spider):    name = "jd"    allowed_domains = ["jd.com"]    start_urls = []    #获取前十页的链接    for i in range(1, 11):        url = "https://search.jd.com/Search?keyword=手机&enc=utf-8&page=" + str(2 * i - 1)        start_urls.append(url)    #获取商品的链接,标题,价格    def parse(self, response):        item = JdPhoneItem()        # 获取标题        item["title"]=response.xpath("//div[@class='p-name p-name-type-2']/a[@target='_blank']/@title").extract()        #得到价格        item["price"] = response.xpath("//div[@class='p-price']/strong/@data-price").extract()        #得到链接        item["url"] = response.xpath('//div[@class="p-name p-name-type-2"]/a[@target="_blank"]/@href').extract()        #将链接存入txt文件中,方便抓取评论,        for i in range(0,len(item["url"])):            #过滤无用链接            pattern = 'https'            bool=re.match(pattern, item["url"][i])            if (bool):                continue            else:                with open('product_url.txt', 'a') as f:                    f.write(item["url"][i]+'\n')        return itemclass CommentSpider(scrapy.Spider):    name = "comment"    #打开存放链接得txt文件    links = open("product_url.txt")    link = links.readlines()    #从商品链接中提取商品id,并构造评论页url    for i in range(1,2):        pattern = r'(\d+)\.html$'        #这里我们读取的评论是单个手机的评论        #可以改变link[]的下标索引来读取不同的手机的评论        id = re.findall(pattern, link[0])        # 得到评论数        commentUrl = "https://club.jd.com/comment/productCommentSummaries.action?referenceIds=" + str(id[0])        commentData = urllib.request.urlopen(commentUrl).read().decode("utf-8", "ignore")        patt1 = r'"CommentCount":(\d+),'        comment_num = re.findall(patt1, commentData)        #得到评论页数        if int(comment_num[0]) % 30 == 0:            comment_page_num= int(int(comment_num[0])/30)        else :            comment_page_num = int(int(comment_num[0])/30)+1        start_urls = []        for i in range(1,comment_page_num+1):            url = "http://club.jd.com/review/" + str(id[0]) + "-1-"+str(i)+"-0.html"            start_urls.append(url)    def parse(self, response):        item = CommentItem()        #用户名        item["user_name"] = response.xpath("//div[@class='i-item']/@data-nickname").extract()        #评论内容        item["content"] = response.xpath("//div[@class='comment-content']/dl/dd/text()").extract()        #手机名称        item["phone_name"] = response.xpath("//div[@class='mc']/ul/li[@class='p-name']/a/text()").extract()        return item

 pipelines.py

将数据爬取下来之后,在这里进行筛选、过滤、储存。将第j个商品的标题、价格、链接拿出来重新组合成一个字典,再将字典写入JSON文件中,这样一行显示一个商品的信息,并且是一一对应的。

import codecsimport jsonimport reclass JdphonePipeline(object):    def __init__(self):        #以写入的方式创建或者打开一个文件        self.file = codecs.open("mydata.json","wb",encoding="utf-8")    def process_item(self,item,spider):        for j in range(0,len(item["price"])):            price=item["price"][j]            pattern = 'https'            bool = re.match(pattern, item["url"][j])            if (bool):                continue            else:                url=item["url"][j]                name=item["title"][j]            goods={"price":price,"name":name,"url":url}            i=json.dumps(dict(goods),ensure_ascii=False)            line=i+'\n'            self.file.write(line)        return item    def close_spider(self,spider):        self.file.close()class CommentPipeline(object):    def __init__(self):        self.file = codecs.open("mydata1.json","wb",encoding="utf-8")    def process_item(self, item, spider):        count = 0        # 去掉换行符与回车符        for i in range(0, len(item["content"])):            pattern = re.match('(\r\n)+', item["content"][i])            if (not pattern):                item["content"][count] = item["content"][i]                count += 1            else:                continue        for j in range(0, len(item["user_name"])):            user_name = item["user_name"][j]            content = item["content"][j]            phone_name = item["phone_name"][int(j/30)]            goods1 = {"phone":phone_name,"user_name": user_name, "content": content}            i = json.dumps(dict(goods1), ensure_ascii=False)            line = i + '\n'            self.file.write(line)        return item    def close_spider(self, spider):        self.file.close()

 setting.py

爬虫的相关设置

BOT_NAME = 'scrapy_prj'SPIDER_MODULES = ['scrapy_prj.spiders']NEWSPIDER_MODULE = 'scrapy_prj.spiders'ITEM_PIPELINES = {    #爬手机信息时,用手机通道,将评论通道注释    #爬评论信息时,用评论通道,将手机通道注释    #'scrapy_prj.pipelines.JdphonePipeline': 300,#手机通道    'scrapy_prj.pipelines.CommentPipeline': 300,#评论通道}#关闭cookie信息COOKIES_ENABLED = False#不遵循爬虫协议ROBOTSTXT_OBEY =False#下载延迟DOWNLOAD_DELAY = 0.5





原创粉丝点击