爬取京东手机排名

一.主题式网络爬虫设计方案

1.主题式网络爬虫名称:爬取京东手机信息。

2.主题式网络爬虫爬取的内容与数据特征分析:每个页面(目前141个页面)的商品名称,详情页url以及图片地址,价格,和进入每个手机详情页后在商品介绍里的‘品牌’、‘运行内存’、‘机身存储’、‘摄像头数量’等信息。

3.主题式网络爬虫设计方案概述:思路:使用网络爬虫方式经行数据分析,通过网源代码找到要爬取的数据对象,将爬取到数据经行存储再绘图分析。

scrapy框架快速爬取,xpath数据提取,csv数据保存。

二.主题页面的结构特征分析

1.主题页面的结构特征分析:

scrapy的概念:Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。

scrapy框架的运行流程以及数据传递过程:

  • 爬虫中起始的url构造成request对象-->爬虫中间件-->引擎-->调度器
  • 调度器把request-->引擎-->下载中间件--->下载器
  • 下载器发送请求,获取response响应---->下载中间件---->引擎--->爬虫中间件--->爬虫
  • 爬虫提取url地址,组装成request对象---->爬虫中间件--->引擎--->调度器,重复步骤2
 
   

爬虫提取数据--->引擎--->管道处理和保存数据:

2.Htmls页面解析:

 3.节点(标签)查找方法与遍历方法:

创建项目:

a) 首先创建名为jdSpiderscrapy项目: scrapy startproject jdSpider

b) 然后切换到创建好的项目文件夹:cd jdSpider

c) 创建名为jd的爬虫:scrapy genspider jd list.jd.com(这里的list.jd.com为允许爬取的域名,后面可做相应修改)

三.网络爬虫程序设计

1.数据爬取与采集

 

import re

import scrapy

import requests

class JdSpider(scrapy.Spider):

    num = 1

    # 爬虫名字

    name = 'jd'

    # 允许爬取的域名

    allowed_domains = ['list.jd.com', 'item.jd.com']  # list. 列表页域名  item. 详情页域名

    # 开始爬取的url地址

    start_urls = ['https://list.jd.com/list.html?cat=9987,653,655&page=1&sort=sort_rank_asc&trans=1&JL=6_0_0#J_main']

    # start_urls = ['https://list.jd.com/list.html?cat=9987,653,655&page=143&sort=sort_rank_asc&trans=1&JL=6_0_0#J_main']

    # 数据提取的方法,接收下载中间件传过来的response

    def parse(self, response):

        # print('查看user-Agent是否有变化')

        # print(response.request.headers['User-Agent'])

        # print('-'*100)

        # 利用xpath进行数据提取

        li_list = response.xpath('//li[@class="gl-item"]')

        # 遍历提取出来单个数据

        for li in li_list:

            # 图片链接

            img = li.xpath('./div/div[@class="p-img"]/a/img/@src').extract_first()

            if not img:

                img = li.xpath('./div/div[@class="p-img"]/a/img/@data-lazy-img').extract_first()

            # 商品名称

            name_list = li.xpath('./div/div/a/em/text()').extract()  # extract 返回一个列表

            name = name_list[0] if len(name_list) == 1 else name_list[1]  # 因为京东国际商品名特殊

            # 商品url

            url = li.xpath('./div/div[@class="p-img"]/a/@href').extract_first()

            # 提取商品id

            sku_id = re.search(r'\d+', url).group()

            # 调用API获取商品价格

            headers = {"User-Agent": response.request.headers['User-Agent'].decode(),

                       'Connection': 'close'}

            price_response = requests.get("https://p.3.cn/prices/mgets?skuIds="+sku_id, headers=headers)

            # [{'cbf': '0', 'id': 'J_100006947212', 'm': '9999.00', 'op': '1399.00', 'p': '1289.00'}]

            # p为目前价格

            dict_response = price_response.json()[0]  #

            price = dict_response['p']

            # 让pipelines.py处理数据 strip()去除字符串的前后空格符

            # yield {"name": name.strip(), "url": url, "img": img, "price": price}

            data_dict = {"name": name.strip(), "url": url, "img": img, "price": price}

            if len(name_list)==1:

                yield scrapy.Request("https:"+url, callback=self.parse_detail, meta={"data_dict": data_dict})

            else:

                yield data_dict  # 京东国际不进入详情页,直接进行数据存储

            # break

        print('第', JdSpider.num, "页已爬取完毕")

        JdSpider.num += 1

        # 提取下一页的url

        next_page_url = response.xpath("//a[@class='pn-next']/@href").extract_first()

        # print('-'*200)

        # print(next_page_url, type(next_page_url))

        # print('-'*200)

        if next_page_url:

            yield scrapy.Request('https://list.jd.com'+next_page_url, callback=self.parse)

    def parse_detail(self, response):

        """处理每个商品详情"""

        data_dict = response.meta["data_dict"]

        if response.status == 200:

            # 品牌

            brand = response.xpath('//ul[@id="parameter-brand"]/li/@title').extract_first()

            if brand:

                # 普通商品

                data_dict["品牌"] = brand

                # 其他数据

                li_list = response.xpath('//ul[@class="parameter2 p-parameter-list"]/li')

                for li in li_list:

                    data = li.xpath('./text()').extract_first()

                    # 正则提取描述和数据

                    ret = re.match(r'(.+?):(.+)', data)  # 为中文:  ?非贪婪

                    key = ret.group(1)

                    value = ret.group(2)

                    data_dict[key] = value

            # else:

            #     # 京东国际

            #     li_list = response.xpath('//ul[@class="parameter2"]/li')

            #     for li in li_list:

            #         data = li.xpath('./text()').extract_first()

            #         if "店铺: " == data:

            #             data_dict["店铺"] = li.xpath('./a/text()').extract_first()

            #             continue

            #         # 正则提取描述和数据

            #         ret = re.match(r'(.+?):(.+)', data)  # 为中文:  ?非贪婪

            #         key = ret.group(1)

            #         value = ret.group(2)

            #         data_dict[key] = value

            # 让pipelines.py处理数据

            yield data_dict

from pymongo import MongoClient

import csv

# Define your item pipelines here

#

# Don't forget to add your pipeline to the ITEM_PIPELINES setting

# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html

fieldnames = ['name', 'url', 'img', 'price', '品牌', '商品名称', "商品编号",

              "商品毛重", "商品产地", "CPU型号", "运行内存", "机身存储", "存储卡",

              "摄像头数量", "后摄主摄像素", "前摄主摄像素", "主屏幕尺寸(英寸)",

              "分辨率", "屏幕比例", "屏幕前摄组合", "充电器", "热点", "特殊功能",

              "操作系统", "游戏性能", "电池容量(mAh)", "机身颜色", "屏占比",

              "充电功率", "游戏配置", "老人机配置", "店铺", "货号"]

class JdspiderPipeline(object):

    def open_spider(self, spider):  # 在爬虫开启的时候仅执行一次

        print('爬虫开启')

        # # 链接mongoDB数据库

        # client = MongoClient("127.0.0.1", 27017)

        # self.collection = client["jd"]["info"]  # 数据库名为jd,表名为info  没有则创建

        with open('data.csv', 'w',  newline='') as csvfile:

            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

            writer.writeheader()

    def close_spider(self, spider):  # 在爬虫关闭的时候仅执行一次

        print('爬虫关闭')

    def process_item(self, item, spider):

        # # 插入数据

        # print(item)

        # self.collection.insert(item)

        with open('data.csv', 'a', newline='') as csvfile:

            writer = csv.DictWriter(csvfile,  fieldnames=fieldnames)

            writer.writerow(item)

2.数据清洗和处理:

可以在settings中设置ROBOTS协议

 

设置日志等级:

 

 3.文本分析:

为了实现不同的请求有不同的user_agent,我们可在settings.py中添加列表USER_AGENTS_LIST:

 

并在middlewares.py中完善代码:

 

这时候还需回到setting.py中开启中间件,从而实现每次请求进行随机选取user_agent:

 

 4.数据分析与可视化(例如:数据柱形图,直方图,散点图,合图,分布图):

绘制分布图:

5.根据数据之间的关系,分析两个变量之间的相关系数,画出散点图,并建立变量之间的回归方程:

 

 6.数据持久化:

 7.完整程序代码:

import re

import scrapy

import requests

class JdSpider(scrapy.Spider):

    num = 1

    # 爬虫名字

    name = 'jd'

    # 允许爬取的域名

    allowed_domains = ['list.jd.com', 'item.jd.com']  # list. 列表页域名  item. 详情页域名

    # 开始爬取的url地址

    start_urls = ['https://list.jd.com/list.html?cat=9987,653,655&page=1&sort=sort_rank_asc&trans=1&JL=6_0_0#J_main']

    # start_urls = ['https://list.jd.com/list.html?cat=9987,653,655&page=143&sort=sort_rank_asc&trans=1&JL=6_0_0#J_main']

    # 数据提取的方法,接收下载中间件传过来的response

    def parse(self, response):

        # print('查看user-Agent是否有变化')

        # print(response.request.headers['User-Agent'])

        # print('-'*100)

        # 利用xpath进行数据提取

        li_list = response.xpath('//li[@class="gl-item"]')

        # 遍历提取出来单个数据

        for li in li_list:

            # 图片链接

            img = li.xpath('./div/div[@class="p-img"]/a/img/@src').extract_first()

            if not img:

                img = li.xpath('./div/div[@class="p-img"]/a/img/@data-lazy-img').extract_first()

            # 商品名称

            name_list = li.xpath('./div/div/a/em/text()').extract()  # extract 返回一个列表

            name = name_list[0] if len(name_list) == 1 else name_list[1]  # 因为京东国际商品名特殊

            # 商品url

            url = li.xpath('./div/div[@class="p-img"]/a/@href').extract_first()

            # 提取商品id

            sku_id = re.search(r'\d+', url).group()

            # 调用API获取商品价格

            headers = {"User-Agent": response.request.headers['User-Agent'].decode(),

                       'Connection': 'close'}

            price_response = requests.get("https://p.3.cn/prices/mgets?skuIds="+sku_id, headers=headers)

            # [{'cbf': '0', 'id': 'J_100006947212', 'm': '9999.00', 'op': '1399.00', 'p': '1289.00'}]

            # p为目前价格

            dict_response = price_response.json()[0]  #

            price = dict_response['p']

            # 让pipelines.py处理数据 strip()去除字符串的前后空格符

            # yield {"name": name.strip(), "url": url, "img": img, "price": price}

            data_dict = {"name": name.strip(), "url": url, "img": img, "price": price}

            if len(name_list)==1:

                yield scrapy.Request("https:"+url, callback=self.parse_detail, meta={"data_dict": data_dict})

            else:

                yield data_dict  # 京东国际不进入详情页,直接进行数据存储

            # break

        print('第', JdSpider.num, "页已爬取完毕")

        JdSpider.num += 1

        # 提取下一页的url

        next_page_url = response.xpath("//a[@class='pn-next']/@href").extract_first()

        # print('-'*200)

        # print(next_page_url, type(next_page_url))

        # print('-'*200)

        if next_page_url:

            yield scrapy.Request('https://list.jd.com'+next_page_url, callback=self.parse)

    def parse_detail(self, response):

        """处理每个商品详情"""

        data_dict = response.meta["data_dict"]

        if response.status == 200:

            # 品牌

            brand = response.xpath('//ul[@id="parameter-brand"]/li/@title').extract_first()

            if brand:

                # 普通商品

                data_dict["品牌"] = brand

                # 其他数据

                li_list = response.xpath('//ul[@class="parameter2 p-parameter-list"]/li')

                for li in li_list:

                    data = li.xpath('./text()').extract_first()

                    # 正则提取描述和数据

                    ret = re.match(r'(.+?):(.+)', data)  # 为中文:  ?非贪婪

                    key = ret.group(1)

                    value = ret.group(2)

                    data_dict[key] = value

            # else:

            #     # 京东国际

            #     li_list = response.xpath('//ul[@class="parameter2"]/li')

            #     for li in li_list:

            #         data = li.xpath('./text()').extract_first()

            #         if "店铺: " == data:

            #             data_dict["店铺"] = li.xpath('./a/text()').extract_first()

            #             continue

            #         # 正则提取描述和数据

            #         ret = re.match(r'(.+?):(.+)', data)  # 为中文:  ?非贪婪

            #         key = ret.group(1)

            #         value = ret.group(2)

            #         data_dict[key] = value

            # 让pipelines.py处理数据

            yield data_dict

from pymongo import MongoClient

import csv

# Define your item pipelines here

#

# Don't forget to add your pipeline to the ITEM_PIPELINES setting

# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html

fieldnames = ['name', 'url', 'img', 'price', '品牌', '商品名称', "商品编号",

              "商品毛重", "商品产地", "CPU型号", "运行内存", "机身存储", "存储卡",

              "摄像头数量", "后摄主摄像素", "前摄主摄像素", "主屏幕尺寸(英寸)",

              "分辨率", "屏幕比例", "屏幕前摄组合", "充电器", "热点", "特殊功能",

              "操作系统", "游戏性能", "电池容量(mAh)", "机身颜色", "屏占比",

              "充电功率", "游戏配置", "老人机配置", "店铺", "货号"]

class JdspiderPipeline(object):

    def open_spider(self, spider):  # 在爬虫开启的时候仅执行一次

        print('爬虫开启')

        # # 链接mongoDB数据库

        # client = MongoClient("127.0.0.1", 27017)

        # self.collection = client["jd"]["info"]  # 数据库名为jd,表名为info  没有则创建

        with open('data.csv', 'w',  newline='') as csvfile:

            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

            writer.writeheader()

    def close_spider(self, spider):  # 在爬虫关闭的时候仅执行一次

        print('爬虫关闭')

    def process_item(self, item, spider):

        # # 插入数据

        # print(item)

        # self.collection.insert(item)

        with open('data.csv', 'a', newline='') as csvfile:

            writer = csv.DictWriter(csvfile,  fieldnames=fieldnames)

            writer.writerow(item)

完善代码:

from jdSpider.settings import USER_AGENTS_LIST

class UserAgentMiddleware(obkect):

      def process_request(self,request,spider):

            user_agent=random.choice(USER_AGENTS_LIST)

            request.headers['User-Agent']=user_agent

            request.headers["Connection"]="close"

class CheckUA(object):

       def process_response(self,request,response,spider):

             return response

 """使用scatter()绘制散点图"""
import matplotlib.pyplot as plt
 
x_values = range(1, 1001)
y_values = [x*x for x in x_values]
'''
scatter() 
x:横坐标 y:纵坐标 s:点的尺寸
'''
plt.scatter(x_values, y_values, s=10)
 
# 设置图表标题并给坐标轴加上标签
plt.title('Square Numbers', fontsize=24)
plt.xlabel('Value', fontsize=14)
plt.ylabel('Square of Value', fontsize=14)
 
# 设置刻度标记的大小
plt.tick_params(axis='both', which='major', labelsize=14)
 
# 设置每个坐标轴的取值范围
plt.axis([0, 1100, 0, 1100000])
plt.show()
 
四.结论
1.经过对主题数据的分析与可视化,可以得到以下结论:苹果以及华为在手机界较为畅销
2.对本次程序设计任务完成的情况做一个简单的小结。
小结:通过这次学习机会,我认识到自己还有很多不足的地方,有很多空间还可以提升,在本次学习中也学到了一些知识。

猜你喜欢

转载自www.cnblogs.com/cmmmmm/p/12758152.html