Python爬虫学习-第四篇 Scrapy框架抓取唯品会数据

2023-11-17

上篇博文讲述了scrapy的框架和组件,对于scrapy有了基本的了解,那么我们进入今天的正题:使用Scrapy框架爬取数据。

1.创建Scrapy项目

创建Scrapy工程文件的命令:

 scrapy startproject scrapytest

  此命令是python默认目下创建的工程。

指定目录文件下创建项目:

1.进入指定目录  cd D:\workspaces 

2.该目录下执行:scrapy startproject scrapytest 

2.scrpay项目结构

 使用PyCharm,打开scrpy的工程文件,效果如下:

2.1 spiders 文件夹就是我们编写spider存放的目录

2.2 items是定义数据类型

2.3 pipeline 负责处理被spider提取出来的item

2.4 Middlewares 默认两个中间件,一个spider 一个是download

2.5 setting 配置信息 默认:

 3.抓取某品会的纸尿裤数据

     3.1 定义数据

class DiaperItem(scrapy.Item):
    diaper_name = scrapy.Field() #纸尿裤商品名称
    diaper_price = scrapy.Field()#价格
    diaper_url = scrapy.Field()  #详情路径
    diaper_source_shop = scrapy.Field() #来源商城(默认为某品会)

   3.2 抓取目标分析

 

 

 

  目标是抓取上图所有的纸尿裤数据。

        3.2.1抓取页面代码

       通过写spider直接访问路径:https://category.vip.com/suggest.php?keyword=纸尿裤

from scrapy.spiders import Spider
from scrapy.http.request import Request


class vipShopSpider(Spider):
    name = "vipshopSpider"
    allowed_domains = ["category.vip.com"]
    start_url = 'https://category.vip.com/suggest.php?keyword=%E7%BA%B8%E5%B0%BF%E8%A3%A4'

    def start_requests(self):
        yield Request(url=self.start_url, callback=self.parse)

    def parse(self, response):
        body = response.body.decode('utf-8')

        pass

其中name就是爬虫的名称,必有字段

allowed_domains 允许爬去站点的域名,此域名内的访问才算有效。

start_url自定义参数,爬虫开始的爬去的页面路径。

start_request第一次请求,url请求页面路径,callback回调函数。

parse 自定义的方法,用于解析html ,主要爬取规则在这里实现。

通过pycharm 配置参数,调试爬虫,获取响应的内容body,用于我们第二次分析.

配置调试步骤:

填入python命令行路径  和执行scrapy的命令:crawl  vipShopSpider

debug运行 ,设置断点,查看body:

复制body ,得到访问结果。经过分析,我们发现body没有商品的信息,得到是一段未经过js渲染的代码:

  那该怎么办呢,我们用到与scrpy配套的js渲染中间件splash,通过这个splash,我们可以得到渲染后的body。

 安装splash很简单,只需在docker环境 安装splash就可以了(这个不是此篇文章的重点)。具体百度。

 splash安装成功后 界面如下:

 

 setting配置splash:

SPLASH_URL = '你的splash的url'

DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}

SPIDER_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}

DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'

HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'

修改spider:

  script = """
                  function main(splash, args)
                     splash:go(args.url)
                     local scroll_to = splash:jsfunc("window.scrollTo")
                     scroll_to(0, 2800)
                     splash:set_viewport_full()
                     splash:wait(5)
                     return {html=splash:html()}
                   end
                 """

    def start_requests(self):
        #yield Request(url=self.start_url, callback=self.parse)
        yield SplashRequest(url=self.start_url, callback=self.parse, endpoint='execute',
                            args={'lua_source': self.script})

script的lua脚本,作用模拟拖动鼠标到页面最低端,保证页面把当前网页的数据加载完成。

再次debug运行爬虫,抓取body,查看最终的html代码。看到产品名称,价格信息。

    3.2.2抓取规则

     从html代码中获取到制定数据,selector(选择器)就在这时候大显身手,scapy选择器是依赖于lxml库,在我的博文《Python爬虫学习-第三篇 Scrapy框架初探和安装》提到过,所以在这儿我就不多讲,直接贴出我的筛选规则代码:

  def parse(self, response):
        sel = Selector(response)
        items = sel.xpath('//div[@class="goods-list-item  c-goods  J_pro_items"]')

        for data in items:
            diaper_name = data.xpath('.//h4[@class="goods-info goods-title-info"]/a/@title').extract_first()
            diaper_price = data.xpath(
                './/div[@class="goods-price-wrapper"]/em/span[@class="price"]/text()').extract_first()
            diaper_url = data.xpath('.//h4[@class="goods-info goods-title-info"]/a/@href').extract_first()

            shop_diaper_item = DiaperItem()
            shop_diaper_item['diaper_name'] = diaper_name
            shop_diaper_item['diaper_price'] = (re.findall(r"\d+\.?\d*", diaper_price))[0]
            shop_diaper_item['diaper_url'] = 'https:' + diaper_url
            shop_diaper_item['diaper_source_shop'] = '唯品会'

            yield shop_diaper_item

        next_url = sel.xpath(
            '//div[@class="m-cat-paging ui-paging"]/a[@class="cat-paging-next next"]/@href').extract_first()

        if next_url is not None:
            next_url = response.urljoin(next_url)
            yield SplashRequest(next_url, callback=self.parse, endpoint='execute', args={'lua_source': self.script})

      第一步:  sel = Selector(response)
        items = sel.xpath('//div[@class="goods-list-item  c-goods  J_pro_items"]')  选取class是"goods-list-item  c-goods  J_pro_items"的元素

      第二步:遍历选取的元素,找到名称、价格、详情url,赋值给自定义DiaperItem,返回DiaperItem

      第三步:找取下一页:

       next_url = sel.xpath(
            '//div[@class="m-cat-paging ui-paging"]/a[@class="cat-paging-next next"]/@href').extract_first() 找取分页的下一页href。得到类似的结果:

判断是否为空,不为空,拼接成类似https://category.vip.com/suggest.php?keyword=纸尿裤&page=2&count=100&suggestType=brand#catPerPos的链接

在加入splash的渲染中间件,循环调取。

   ps:scrapy 是默认开启了,url去重的访问,所以即使有重复url路径请求,scrapy会自动清除。

   3.2.3保存数据

      使用pipeline来处理数据,使用mssql数据库来存储数据:

from DiaperService.MssqlService import MssqlService


class DiaperPipeline(object):

    def process_item(self, item, spider):
        name = item['diaper_name'].replace("'", "''")

        ms = MssqlService(server='192.168.200.200', user='sa', password='123456aA', db_name='test')
        sql = 'insert into [dbo].[Diaper](Name,Price,DetailUrl,SourceShop) ' \
              'values(\'%s\',%f,\'%s\',\'%s\') ' % (name,
                                                    float(item['diaper_price']),
                                                    item['diaper_url'],
                                                    item['diaper_source_shop'])
        # print(sql)
        ms.exec_non_query(sql)
        return item

封装的mssql服务:

import pymssql


class MssqlService(object):
    def __init__(self, server, user, password, db_name):
        self.host = server
        self.user = user
        self.password = password
        self.database = db_name
        self.conn = self.__get_Conn()

    def __get_Conn(self):
        conn = pymssql.connect(self.host, self.user, self.password, self.database)
        return conn

    def exec_query(self, sql):
        cur = self.conn.cursor()
        cur.execute(sql)
        result_list = cur.fetchall()
        cur.close()
        return result_list

    def exec_non_query(self, sql):
        cur = self.conn.cursor()
        cur.execute(sql)
        self.conn.commit()
        cur.close()

setting配置pipeline的优先级300:

ITEM_PIPELINES = {
    'Diaper.pipelines.DiaperPipeline': 300,
}

那么到现在我们已经把爬虫从请求网页,获取相应,解析内容,保存数据的都完成开发,所以我们运行下程序,查看是否成功抓取数据。

数据库中的数据:

 4.总结

      scrapy还有很多强大的功能去探索,比如链式爬虫,能够递归爬取数据,可以配置递归的层级等。同时它的选择器lxml库,筛选查询非常方便快速,相较于正则表达式学习成本更低,更易理解,能让新手快速入门。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python爬虫学习-第四篇 Scrapy框架抓取唯品会数据 的相关文章

  • 赋值运算符左/右侧的不同切片行为

    作为一个来自 C 背景的 Python 新手 Python 3 4 x 中的切片运算符对我来说看起来很荒谬 我只是不明白 特殊规则 背后的设计理念 让我解释一下为什么我说它 特别 一方面 根据 Stack Overflow 的回答here
  • 如何从 QLineEdit 动态获取文本? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 怎样才能得到String Text from QlineEdit 我尝试过像这样 myArea getList 功能是获取字符串值并使用字符
  • 如何使用 eval dataframe 方法在自定义函数中返回 numpy 数组或列表?

    我正在使用 python 3 X 我正在尝试使用eval https pandas pydata org pandas docs stable generated pandas eval html pandas eval数据框方法 包括这样
  • Matplotlib 颤抖比例

    我正在尝试使用 matplotlib 和 quiver 函数绘制一些箭头 但我想使用数组单独选择每个箭头的长度 http matplotlib sourceforge net api pyplot api html matplotlib p
  • 在类中设置默认值

    我正在用 Python 创建一个类 但我不确定如何正确设置默认值 我的目标是为所有类实例设置默认值 也可以通过类方法对其进行修改 但是 我希望在调用方法后恢复初始默认值 我已经能够使用下面所示的代码使其工作 它不是很 漂亮 所以我怀疑这是解
  • 在 cherokee 和 uwsgi 上部署 Flask [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我正在尝试部署一个使用 cherokee 和 uwsgi 开发的 Flask Web 应用程序 我安装了 cherokee 和 uwsgi 并正在工作
  • 给定一个正整数 n,如何打印高度为 n-1 的数字三角形?

    HackerRank 三角任务 https www hackerrank com challenges python quest 1 problem 仅使用算术运算 单个for loop 和一个单一的print陈述 不允许进行字符串操作 约
  • TensorFlow 运算符重载

    有什么区别 tf add x y and x y 在 TensorFlow 中 当您使用以下命令构建图表时 您的计算图表会有什么不同 代替tf add 更一般地说 有 或者其他张量超载的操作 如果至少有一个x or y is a tf Te
  • 匹配字典集。最优雅的解决方案。 Python

    给定两个字典列表 新的和旧的 字典在两个列表中表示相同的对象 我需要找到差异并生成新的字典列表 其中仅包含新字典中的对象和旧字典中的更新属性 例子 list new id 1 name bob desc cool guy id 2 name
  • MAMP Python-MySQLdb 问题:调用 Python 文件后 libssl.1.0.0.dylib 的路径发生变化

    我正在尝试使用 python MySQLdb 访问 MAMP 服务器上的 MySQL 数据库 当我最初尝试使用 python sql 调用 Python 文件来访问 MAMP 上的数据库时 我得到了image not found关于错误li
  • 检查空查询集

    我想确认这是否是检查空查询集的正确方法 如果这就是为什么我会遇到 UNIQUE 约束错误 syn check Synonym objects filter MD objects get filter dict synonym type St
  • 如何将当前登录的用户指定为模型字段的默认值?

    我想做这样的事情 class Task models Model created by models ForeignKey User default LoggedInUser blank True null True related nam
  • django 创建多类型用户的最佳方法

    我想在 django 中创建多个用户 我想知道哪种方法是最好的 class Teachers models Model user models ForeignKey User is teacher models BooleanField d
  • 找出段落中出现的单词

    sentence Alice was not a bit hurt and she jumped up on to her feet in a moment words Alice jumped played 我可以使用filterpyth
  • TypeError: 'module' 对象不可调用错误 driver=webdriver("C:\\Python34\\Lib\\site-packages\\selenium\\webdriver\\chromedriver.exe")

    我在 Pycharm 中遇到类似错误 Traceback most recent call last File C PycharmProjects DemoPyth PythonPack1 Prg1 py line 3 in
  • 标记 pandas 系列中连续的 True 元素组

    我有一系列的 pandas 布尔值 我想标记连续的 True 值组 怎么可能做到这一点 是否可以以矢量化的方式做到这一点 任何帮助将不胜感激 Data A 0 False 1 True 2 True 3 True 4 False 5 Fal
  • 虎鲸失踪

    使用plotly 导出静态图表时遇到小问题 Plotly 无法正确识别我已安装 orca 并且仍然存在与缺少 orca 相关的错误 我尝试更改 orca 目录 但它仍然无法正常工作 谁知道出了什么问题吗 My code import plo
  • 熊猫:SettingWithCopyWarning:[重复]

    这个问题在这里已经有答案了 我尝试使用以下代码将列转换为 日期 df DATE pd to datetime df DATE or df DATE pd to datetime df DATE 但我收到以下错误 Users xyz anac
  • 需要帮助编写扭曲的代理

    我想编写一个简单的代理 可以对请求页面正文中的文本进行打乱 我已经阅读了 stackoverflow 上的部分扭曲文档和其他一些类似的问题 但我有点菜鸟 所以我仍然不明白 我现在就是这样 不知道如何访问和修改页面 from twisted
  • 在 jupyter 笔记本中运行 pytest 测试函数

    我正在制作有关 python 测试选项的演示 我想要演示的技术之一是 pytest 我计划使用 jupyter ipython 笔记本进行演示 理想情况下 我希望能够在单元格中定义一个测试函数 然后使用 pytest 运行该函数 这样我就可

随机推荐