python基于scrapy爬取京东笔记本电脑数据并进行简单处理和分析


Posted in Python onApril 14, 2021

一、环境准备

  • python3.8.3
  • pycharm
  • 项目所需第三方包
pip install scrapy fake-useragent requests selenium virtualenv -i https://pypi.douban.com/simple

1.1 创建虚拟环境

切换到指定目录创建

virtualenv .venv

创建完记得激活虚拟环境

1.2 创建项目

scrapy startproject 项目名称

1.3 使用pycharm打开项目,将创建的虚拟环境配置到项目中来
1.4 创建京东spider

scrapy genspider 爬虫名称 url

1.5 修改允许访问的域名,删除https:

二、问题分析

爬取数据的思路是先获取首页的基本信息,在获取详情页商品详细信息;爬取京东数据时,只返回40条数据,这里,作者使用selenium,在scrapy框架中编写下载器中间件,返回页面所有数据。
爬取的字段分别是:

商品价格

商品评数

商品店家

商品SKU(京东可直接搜索到对应的产品)

商品标题

商品详细信息

三、spider

import re
import scrapy


from lianjia.items import jd_detailItem


class JiComputerDetailSpider(scrapy.Spider):
    name = 'ji_computer_detail'
    allowed_domains = ['search.jd.com', 'item.jd.com']
    start_urls = [
        'https://search.jd.com/Search?keyword=%E7%AC%94%E8%AE%B0%E6%9C%AC%E7%94%B5%E8%84%91&suggest=1.def.0.base&wq=%E7%AC%94%E8%AE%B0%E6%9C%AC%E7%94%B5%E8%84%91&page=1&s=1&click=0']

    def parse(self, response):
        lls = response.xpath('//ul[@class="gl-warp clearfix"]/li')
        for ll in lls:
            item = jd_detailItem()
            computer_price = ll.xpath('.//div[@class="p-price"]/strong/i/text()').extract_first()
            computer_commit = ll.xpath('.//div[@class="p-commit"]/strong/a/text()').extract_first()
            computer_p_shop = ll.xpath('.//div[@class="p-shop"]/span/a/text()').extract_first()
            item['computer_price'] = computer_price
            item['computer_commit'] = computer_commit
            item['computer_p_shop'] = computer_p_shop
            meta = {
                'item': item
            }
            shop_detail_url = ll.xpath('.//div[@class="p-img"]/a/@href').extract_first()
            shop_detail_url = 'https:' + shop_detail_url
            yield scrapy.Request(url=shop_detail_url, callback=self.detail_parse, meta=meta)
        for i in range(2, 200, 2):
            next_page_url = f'https://search.jd.com/Search?keyword=%E7%AC%94%E8%AE%B0%E6%9C%AC%E7%94%B5%E8%84%91&suggest=1.def.0.base&wq=%E7%AC%94%E8%AE%B0%E6%9C%AC%E7%94%B5%E8%84%91&page={i}&s=116&click=0'
            yield scrapy.Request(url=next_page_url, callback=self.parse)

    def detail_parse(self, response):
        item = response.meta.get('item')
        computer_sku = response.xpath('//a[@class="notice J-notify-sale"]/@data-sku').extract_first()
        item['computer_sku'] = computer_sku
        computer_title = response.xpath('//div[@class="sku-name"]/text()').extract_first().strip()
        computer_title = ''.join(re.findall('\S', computer_title))
        item['computer_title'] = computer_title
        computer_detail = response.xpath('string(//ul[@class="parameter2 p-parameter-list"])').extract_first().strip()
        computer_detail = ''.join(re.findall('\S', computer_detail))
        item['computer_detail'] = computer_detail
        yield item

四、item

class jd_detailItem(scrapy.Item):
    # define the fields for your item here like:
    computer_sku = scrapy.Field()
    computer_price = scrapy.Field()
    computer_title = scrapy.Field()
    computer_commit = scrapy.Field()
    computer_p_shop = scrapy.Field()
    computer_detail = scrapy.Field()

五、setting

import random


from fake_useragent import UserAgent
ua = UserAgent()
USER_AGENT = ua.random
ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY = random.uniform(0.5, 1)
DOWNLOADER_MIDDLEWARES = {
    'lianjia.middlewares.jdDownloaderMiddleware': 543
}
ITEM_PIPELINES = {
    'lianjia.pipelines.jd_csv_Pipeline': 300
}

六、pipelines

class jd_csv_Pipeline:
    # def process_item(self, item, spider):
    #     return item
    def open_spider(self, spider):
        self.fp = open('./jd_computer_message.xlsx', mode='w+', encoding='utf-8')
        self.fp.write('computer_sku\tcomputer_title\tcomputer_p_shop\tcomputer_price\tcomputer_commit\tcomputer_detail\n')

    def process_item(self, item, spider):
        # 写入文件
        try:
            line = '\t'.join(list(item.values())) + '\n'
            self.fp.write(line)
            return item
        except:
            pass

    def close_spider(self, spider):
        # 关闭文件
        self.fp.close()

七、middlewares

class jdDownloaderMiddleware:
    def process_request(self, request, spider):
        # 判断是否是ji_computer_detail的爬虫
        # 判断是否是首页
        if spider.name == 'ji_computer_detail' and re.findall(f'.*(item.jd.com).*', request.url) == []:
            options = ChromeOptions()
            options.add_argument("--headless")
            driver = webdriver.Chrome(options=options)
            driver.get(request.url)
            for i in range(0, 15000, 5000):
                driver.execute_script(f'window.scrollTo(0, {i})')
                time.sleep(0.5)
            body = driver.page_source.encode()
            time.sleep(1)
            return HtmlResponse(url=request.url, body=body, request=request)
        return None

八、使用jupyter进行简单的处理和分析

其他文件:百度停用词库、简体字文件
下载第三方包

!pip install seaborn jieba wordcloud PIL  -i https://pypi.douban.com/simple

8.1导入第三方包

import re
import os
import jieba
import wordcloud
import pandas as pd
import numpy as np
from PIL import Image
import seaborn as sns
from docx import Document
from docx.shared import Inches
import matplotlib.pyplot as plt
from pandas import DataFrame,Series

8.2设置可视化的默认字体和seaborn的样式

sns.set_style('darkgrid')
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

8.3读取数据

df_jp = pd.read_excel('./jd_shop.xlsx')

8.4筛选Inteli5、i7、i9处理器数据

def convert_one(s):
    if re.findall(f'.*?(i5).*', str(s)) != []:
        return re.findall(f'.*?(i5).*', str(s))[0]
    elif re.findall(f'.*?(i7).*', str(s)) != []:
        return re.findall(f'.*?(i7).*', str(s))[0]
    elif re.findall(f'.*?(i9).*', str(s)) != []:
        return re.findall(f'.*?(i9).*', str(s))[0]
df_jp['computer_intel'] = df_jp['computer_detail'].map(convert_one)

8.5筛选笔记本电脑的屏幕尺寸范围

def convert_two(s):
    if re.findall(f'.*?(\d+\.\d+英寸-\d+\.\d+英寸).*', str(s)) != []:
        return re.findall(f'.*?(\d+\.\d+英寸-\d+\.\d+英寸).*', str(s))[0]
df_jp['computer_in'] = df_jp['computer_detail'].map(convert_two)

8.6将评论数转化为整形

def convert_three(s):
    if re.findall(f'(\d+)万+', str(s)) != []:
        number = int(re.findall(f'(\d+)万+', str(s))[0]) * 10000
        return number
    elif re.findall(f'(\d+)+', str(s)) != []:
        number = re.findall(f'(\d+)+', str(s))[0]
        return number
df_jp['computer_commit'] = df_jp['computer_commit'].map(convert_three)

8.7筛选出需要分析的品牌

def find_computer(name, s):
    sr = re.findall(f'.*({name}).*', str(s))[0]
    return sr
def convert(s):
    if re.findall(f'.*(联想).*', str(s)) != []:
        return find_computer('联想', s)
    elif re.findall(f'.*(惠普).*', str(s)) != []:
        return find_computer('惠普', s)
    elif re.findall(f'.*(华为).*', str(s)) != []:
        return find_computer('华为', s)
    elif re.findall(f'.*(戴尔).*', str(s)) != []:
        return find_computer('戴尔', s)
    elif re.findall(f'.*(华硕).*', str(s)) != []:
        return find_computer('华硕', s)
    elif re.findall(f'.*(小米).*', str(s)) != []:
        return find_computer('小米', s)
    elif re.findall(f'.*(荣耀).*', str(s)) != []:
        return find_computer('荣耀', s)
    elif re.findall(f'.*(神舟).*', str(s)) != []:
        return find_computer('神舟', s)
    elif re.findall(f'.*(外星人).*', str(s)) != []:
        return find_computer('外星人', s)
df_jp['computer_p_shop'] = df_jp['computer_p_shop'].map(convert)

8.8删除指定字段为空值的数据

for n in ['computer_price', 'computer_commit', 'computer_p_shop', 'computer_sku', 'computer_detail', 'computer_intel', 'computer_in']:
    index_ls = df_jp[df_jp[[n]].isnull().any(axis=1)==True].index
    df_jp.drop(index=index_ls, inplace=True)

8.9查看各品牌的平均价格

plt.figure(figsize=(10, 8), dpi=100)
ax = sns.barplot(x='computer_p_shop', y='computer_price', data=df_jp.groupby(by='computer_p_shop')[['computer_price']].mean().reset_index())
for index,row in df_jp.groupby(by='computer_p_shop')[['computer_price']].mean().reset_index().iterrows():
    ax.text(row.name,row['computer_price'] + 2,round(row['computer_price'],2),color="black",ha="center")
ax.set_xlabel('品牌')
ax.set_ylabel('平均价格')
ax.set_title('各品牌平均价格')
boxplot_fig = ax.get_figure()
boxplot_fig.savefig('各品牌平均价格.png', dpi=400)

python基于scrapy爬取京东笔记本电脑数据并进行简单处理和分析

8.10 查看各品牌的价格区间

plt.figure(figsize=(10, 8), dpi=100)
ax = sns.boxenplot(x='computer_p_shop', y='computer_price', data=df_jp.query('computer_price>500'))
ax.set_xlabel('品牌')
ax.set_ylabel('价格区间')
ax.set_title('各品牌价格区间')
boxplot_fig = ax.get_figure()
boxplot_fig.savefig('各品牌价格区间.png', dpi=400)

python基于scrapy爬取京东笔记本电脑数据并进行简单处理和分析

8.11 查看价格与评论数的关系

df_jp['computer_commit'] = df_jp['computer_commit'].astype('int64')
ax = sns.jointplot(x="computer_commit", y="computer_price", data=df_jp, kind="reg", truncate=False,color="m", height=10)
ax.fig.savefig('评论数与价格的关系.png')

python基于scrapy爬取京东笔记本电脑数据并进行简单处理和分析

8.12 查看商品标题里出现的关键词

import imageio

# 将特征转换为列表
ls = df_jp['computer_title'].to_list()
# 替换非中英文的字符
feature_points = [re.sub(r'[^a-zA-Z\u4E00-\u9FA5]+',' ',str(feature)) for feature in ls]
# 读取停用词
stop_world = list(pd.read_csv('./百度停用词表.txt', engine='python', encoding='utf-8', names=['stopwords'])['stopwords'])
feature_points2 = []
for feature in feature_points:  # 遍历每一条评论
    words = jieba.lcut(feature) # 精确模式,没有冗余.对每一条评论进行jieba分词
    ind1 = np.array([len(word) > 1 for word in words])  # 判断每个分词的长度是否大于1
    ser1 = pd.Series(words)
    ser2 = ser1[ind1] # 筛选分词长度大于1的分词留下
    ind2 = ~ser2.isin(stop_world)  # 注意取反负号
    ser3 = ser2[ind2].unique()  # 筛选出不在停用词表的分词留下,并去重
    if len(ser3) > 0:
        feature_points2.append(list(ser3))
# 将所有分词存储到一个列表中
wordlist = [word for feature in feature_points2 for word in feature]
# 将列表中所有的分词拼接成一个字符串
feature_str =  ' '.join(wordlist)   
# 标题分析
font_path = r'./simhei.ttf'
shoes_box_jpg = imageio.imread('./home.jpg')
wc=wordcloud.WordCloud(
    background_color='black',
    mask=shoes_box_jpg,
    font_path = font_path,
    min_font_size=5,
    max_font_size=50,
    width=260,
    height=260,
)
wc.generate(feature_str)
plt.figure(figsize=(10, 8), dpi=100)
plt.imshow(wc)
plt.axis('off')
plt.savefig('标题提取关键词')

python基于scrapy爬取京东笔记本电脑数据并进行简单处理和分析

8.13 筛选价格在4000到5000,联想品牌、处理器是i5、屏幕大小在15寸以上的数据并查看价格

df_jd_query = df_jp.loc[(df_jp['computer_price'] <=5000) & (df_jp['computer_price']>=4000) & (df_jp['computer_p_shop']=="联想") & (df_jp['computer_intel']=="i5") & (df_jp['computer_in']=="15.0英寸-15.9英寸"), :].copy()
plt.figure(figsize=(20, 10), dpi=100)
ax = sns.barplot(x='computer_sku', y='computer_price', data=df_jd_query)
ax.set_xlabel('联想品牌SKU')
ax.set_ylabel('价格')
ax.set_title('酷睿i5处理器屏幕15寸以上各SKU的价格')
boxplot_fig = ax.get_figure()
boxplot_fig.savefig('酷睿i5处理器屏幕15寸以上各SKU的价格.png', dpi=400)

python基于scrapy爬取京东笔记本电脑数据并进行简单处理和分析

8.14 筛选价格在4000到5000,戴尔品牌、处理器是i7、屏幕大小在15寸以上的数据并查看价格

df_jp_daier = df_jp.loc[(df_jp['computer_price'] <=5000) & (df_jp['computer_price']>=4000) & (df_jp['computer_p_shop']=="戴尔") & (df_jp['computer_intel']=="i7") & (df_jp['computer_in']=="15.0英寸-15.9英寸"), :].copy()
plt.figure(figsize=(10, 8), dpi=100)
ax = sns.barplot(x='computer_sku', y='computer_price', data=df_jp_daier)
ax.set_xlabel('戴尔品牌SKU')
ax.set_ylabel('价格')
ax.set_title('酷睿i7处理器屏幕15寸以上各SKU的价格')
boxplot_fig = ax.get_figure()
boxplot_fig.savefig('酷睿i7处理器屏幕15寸以上各SKU的价格.png', dpi=400)

python基于scrapy爬取京东笔记本电脑数据并进行简单处理和分析

8.15 不同Intel处理器品牌的价格

plt.figure(figsize=(10, 8), dpi=100)
ax = sns.barplot(x='computer_p_shop', y='computer_price', data=df_jp, hue='computer_intel')
ax.set_xlabel('品牌')
ax.set_ylabel('价格')
ax.set_title('不同酷睿处理器品牌的价格')
boxplot_fig = ax.get_figure()
boxplot_fig.savefig('不同酷睿处理器品牌的价格.png', dpi=400)

python基于scrapy爬取京东笔记本电脑数据并进行简单处理和分析

8.16 不同尺寸品牌的价格

plt.figure(figsize=(10, 8), dpi=100)
ax = sns.barplot(x='computer_p_shop', y='computer_price', data=df_jp, hue='computer_in')
ax.set_xlabel('品牌')
ax.set_ylabel('价格')
ax.set_title('不同尺寸品牌的价格')
boxplot_fig = ax.get_figure()
boxplot_fig.savefig('不同尺寸品牌的价格.png', dpi=400)

python基于scrapy爬取京东笔记本电脑数据并进行简单处理和分析

以上就是python基于scrapy爬取京东笔记本电脑数据并进行简单处理和分析的详细内容,更多关于python 爬取京东数据的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
wxPython框架类和面板类的使用实例
Sep 28 Python
python实现删除文件与目录的方法
Nov 10 Python
Python实现队列的方法
May 26 Python
Python的装饰器模式与面向切面编程详解
Jun 21 Python
安装python时MySQLdb报错的问题描述及解决方法
Mar 20 Python
python web框架Flask实现图形验证码及验证码的动态刷新实例
Oct 14 Python
Python递归调用实现数字累加的代码
Feb 25 Python
详解用Python进行时间序列预测的7种方法
Mar 13 Python
Pytorch 卷积中的 Input Shape用法
Jun 29 Python
Django生成数据库及添加用户报错解决方案
Oct 09 Python
python编程学习使用管道Pipe编写优化代码
Nov 20 Python
分享Python获取本机IP地址的几种方法
Mar 17 Python
深度学习小工程练习之垃圾分类详解
python3美化表格数据输出结果的实现代码
Apr 14 #Python
Python生成九宫格图片的示例代码
用Python写一个简易版弹球游戏
python urllib库的使用详解
Apr 13 #Python
用Python将库打包发布到pypi
python xlwt模块的使用解析
You might like
PHP和Mysqlweb应用开发核心技术 第1部分 Php基础-1 开始了解php
2011/07/03 PHP
thinkphp3.0 模板中函数的使用
2012/11/13 PHP
php绘图中显示不出图片的原因及解决
2014/03/05 PHP
PHP中使用file_get_contents post数据代码例子
2015/02/13 PHP
php实现中文字符截取防乱码方法汇总
2015/04/29 PHP
php5.3/5.4/5.5/5.6/7常见新增特性汇总整理
2020/02/27 PHP
Jquery 类网页微信二维码图块滚动效果具体实现
2013/10/14 Javascript
javascript实现淘宝幻灯片广告展示效果
2015/04/27 Javascript
jquery实现简单Tab切换菜单效果
2020/07/17 Javascript
移动适配的几种方案(三种方案)
2016/11/25 Javascript
JS数组搜索之折半搜索实现方法分析
2017/03/27 Javascript
Three.js利用Detector.js插件如何实现兼容性检测详解
2017/09/26 Javascript
Vuex提升学习篇
2018/01/11 Javascript
vue2.0组件之间传值、通信的多种方式(干货)
2018/02/10 Javascript
vue src动态加载请求获取图片的方法
2018/10/17 Javascript
JavaScript学习笔记之基于定时器实现图片无缝滚动功能详解
2019/01/09 Javascript
JS实现滚动条触底加载更多
2019/09/19 Javascript
关于vue属性使用和不使用冒号的区别说明
2020/10/22 Javascript
[01:13:51]TNC vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
python实现发送邮件及附件功能
2021/03/02 Python
Python函数装饰器实现方法详解
2018/12/22 Python
python简单实现AES加密和解密
2019/03/28 Python
Python3分析处理声音数据的例子
2019/08/27 Python
python 追踪except信息方式
2020/04/25 Python
python_matplotlib改变横坐标和纵坐标上的刻度(ticks)方式
2020/05/16 Python
tensorflow pb to tflite 精度下降详解
2020/05/25 Python
几款好用的python工具库(小结)
2020/10/20 Python
使用canvas生成含有微信头像的邀请海报没有微信头像问题
2019/10/29 HTML / CSS
ProForm英国站点:健身房和健身器材网上商店
2019/06/05 全球购物
九月份红领巾广播稿
2014/01/22 职场文书
物流创业计划书
2014/02/01 职场文书
超市仓管员岗位职责范本
2014/09/18 职场文书
毕业设计致谢语
2015/05/14 职场文书
校运会加油稿大全
2015/07/22 职场文书
html css3不拉伸图片显示效果
2021/06/07 HTML / CSS
详解解Django 多对多表关系的三种创建方式
2021/08/23 Python