第46讲:遇到动态页面怎么办?详解渲染页面爬取

2023-11-06

前面我们已经介绍了 Scrapy 的一些常见用法,包括服务端渲染页面的抓取和 API 的抓取,Scrapy 发起 Request 之后,返回的 Response 里面就包含了想要的结果。

但是现在越来越多的网页都已经演变为 SPA 页面,其页面在浏览器中呈现的结果是经过 JavaScript 渲染得到的,如果我们使用 Scrapy 直接对其进行抓取的话,其结果和使用 requests 没有什么区别。

那我们真的要使用 Scrapy 完成对 JavaScript 渲染页面的抓取应该怎么办呢?

之前我们介绍了 Selenium 和 Pyppeteer 都可以实现 JavaScript 渲染页面的抓取,那用了 Scrapy 之后应该这么办呢?Scrapy 能和 Selenium 或 Pyppeteer 一起使用吗?答案是肯定的,我们可以将 Selenium 或 Pyppeteer 通过 Downloader Middleware 和 Scrapy 融合起来,实现 JavaScript 渲染页面的抓取,本节我们就来了解下它的实现吧。

回顾

在前面我们介绍了 Downloader Middleware 的用法,在 Downloader Middleware 中有三个我们可以实现的方法 process_requestprocess_response 以及 process_exception 方法。

  • 我们再看下 process_request 方法和其不同的返回值的效果:
    当返回为 None 时,Scrapy 将继续处理该 Request,接着执行其他 Downloader Middleware 的 process_request 方法,一直到 Downloader 把 Request 执行完后得到 Response 才结束。这个过程其实就是修改 Request 的过程,不同的 Downloader Middleware 按照设置的优先级顺序依次对 Request 进行修改,最后送至 Downloader 执行。

  • 当返回为 Response 对象时,更低优先级的 Downloader Middleware 的 process_request 和 process_exception 方法就不会被继续调用,每个 Downloader Middleware 的 process_response 方法转而被依次调用。调用完毕之后,直接将 Response 对象发送给 Spider 来处理。

  • 当返回为 Request 对象时,更低优先级的 Downloader Middleware 的 process_request 方法会停止执行。这个 Request 会重新放到调度队列里,其实它就是一个全新的 Request,等待被调度。如果被 Scheduler 调度了,那么所有的 Downloader Middleware 的 process_request 方法都会被重新按照顺序执行。

  • 如果 IgnoreRequest 异常抛出,则所有的 Downloader Middleware 的 process_exception 方法会依次执行。如果没有一个方法处理这个异常,那么 Request 的 errorback 方法就会回调。如果该异常还没有被处理,那么它便会被忽略。

这里我们注意到第二个选项,当返回结果为 Response 对象时,低优先级的 process_request 方法就不会被继续调用了,这个 Response 对象会直接经由 process_response 方法处理后转交给 Spider 来解析。

然后再接着想一想,process_request 接收的参数是 request,即 Request 对象,怎么会返回 Response 对象呢?原因可想而知了,这个 Request 对象不再经由 Scrapy 的 Downloader 来处理了,而是在 process_request 方法里面直接就完成了 Request 的发送操作,然后在得到了对应的 Response 结果后再将其返回就好了。

那么对于 JavaScript 渲染的页面来说,照这个方法来做,我们就可以把 Selenium 或 Pyppeteer 加载页面的过程在 process_request 方法里面实现,得到网页渲染完后的源代码后直接构造 Response 返回即可,这样我们就完成了借助 Downloader Middleware 实现 Scrapy 爬取动态渲染页面的过程。

案例

本节我们就用实例来讲解一下 Scrapy 和 Pyppeteer 实现 JavaScript 渲染页面抓取的流程。

本节使用的实例网站为 https://dynamic5.scrape.center/,这是一个 JavaScript 渲染页面,其内容是一本本的图书信息。
在这里插入图片描述

同时这个网站的页面带有分页功能,只需要在 URL 加上 /page/ 和页码就可以跳转到下一页,如 https://dynamic5.scrape.center/page/2 就是第二页内容,https://dynamic5.scrape.center/page/3 就是第三页内容。

那我们这个案例就来试着爬取前十页的图书信息吧。

实现

首先我们来新建一个项目,叫作 scrapypyppeteer,命令如下:

scrapy startproject scrapypyppeteer

接着进入项目,然后新建一个 Spider,名称为 book,命令如下:

cd scrapypyppeteer
scrapy genspider book dynamic5.scrape.center

这时候可以发现在项目的 spiders 文件夹下就出现了一个名为 spider.py 的文件,内容如下:

# -*- coding: utf-8 -*-
import scrapy
​
class BookSpider(scrapy.Spider):
    name = 'book'
    allowed_domains = ['dynamic5.scrape.center']
    start_urls = ['http://dynamic5.scrape.center/']def parse(self, response):
        pass

首先我们构造列表页的初始请求,实现一个 start_requests 方法,如下所示:

# -*- coding: utf-8 -*-
from scrapy import Request, Spider

class BookSpider(Spider):
    name = 'book'
    allowed_domains = ['dynamic5.scrape.center']
    
    base_url = 'https://dynamic5.scrape.center/page/{page}'
    max_page = 10
    
    def start_requests(self):
        for page in range(1, self.max_page + 1):
            url = self.base_url.format(page=page)
            yield Request(url, callback=self.parse_index)
    
    def parse_index(self, response):
        print(response.text)

这时如果我们直接运行这个 Spider,在 parse_index 方法里面打印输出 Response 的内容,结果如下:
在这里插入图片描述
我们可以发现所得到的内容并不是页面渲染后的真正 HTML 代码。此时如果我们想要获取 HTML 渲染结果的话就得使用 Downloader Middleware 实现了。

这里我们直接以一个我已经写好的组件来演示了,组件的名称叫作 GerapyPyppeteer,组件里已经写好了 Scrapy 和 Pyppeteer 结合的中间件,下面我们来详细介绍下。

我们可以借助于 pip3 来安装组件,命令如下:

pip3 install gerapy-pyppeteer

GerapyPyppeteer 提供了两部分内容,一部分是 Downloader Middleware,一部分是 Request。
首先我们需要开启中间件,在 settings 里面开启 PyppeteerMiddleware,配置如下:

DOWNLOADER_MIDDLEWARES = {
    'gerapy_pyppeteer.downloadermiddlewares.PyppeteerMiddleware': 543,
}

然后我们把上文定义的 Request 修改为 PyppeteerRequest 即可:

# -*- coding: utf-8 -*-
from gerapy_pyppeteer import PyppeteerRequest
from scrapy import Request, Spider
​
class BookSpider(Spider):
    name = 'book'
    allowed_domains = ['dynamic5.scrape.center']
    
    base_url = 'https://dynamic5.scrape.center/page/{page}'
    max_page = 10
    
    def start_requests(self):
        for page in range(1, self.max_page + 1):
            url = self.base_url.format(page=page)
            yield PyppeteerRequest(url, callback=self.parse_index, wait_for='.item .name')
    
    def parse_index(self, response):
        print(response.text)

这样其实就完成了 Pyppeteer 的对接了,非常简单。
这里 PyppeteerRequest 和原本的 Request 多提供了一个参数,就是 wait_for,通过这个参数我们可以指定 Pyppeteer 需要等待特定的内容加载出来才算结束,然后才返回对应的结果。

为了方便观察效果,我们把并发限制修改得小一点,然后把 Pyppeteer 的 Headless 模式设置为 False:

CONCURRENT_REQUESTS = 3
GERAPY_PYPPETEER_HEADLESS = False

这时我们重新运行 Spider,就可以看到在爬取的过程中,Pyppeteer 对应的 Chromium 浏览器就弹出来了,并逐个加载对应的页面内容,加载完成之后浏览器关闭。
另外观察下控制台,我们发现对应的结果也就被提取出来了,如图所示:
在这里插入图片描述
这时候我们再重新修改下 parse_index 方法,提取对应的每本书的名称和作者即可:

def parse_index(self, response):
    for item in response.css('.item'):
        name = item.css('.name::text').extract_first()
        authors = item.css('.authors::text').extract_first()
        name = name.strip() if name else None
        authors = authors.strip() if authors else None
        yield {
            'name': name,
            'authors': authors
        }

重新运行,即可发现对应的名称和作者就被提取出来了,运行结果如下:
在这里插入图片描述
这样我们就借助 GerapyPyppeteer 完成了 JavaScript 渲染页面的爬取。

原理分析

但上面仅仅是我们借助 GerapyPyppeteer 实现了 Scrapy 和 Pyppeteer 的对接,但其背后的原理是怎样的呢?

我们可以详细分析它的源码,其 GitHub 地址为 https://github.com/Gerapy/GerapyPyppeteer

首先通过分析可以发现其最核心的内容就是实现了一个 PyppeteerMiddleware,这是一个 Downloader Middleware,这里最主要的就是 process_request 的实现,核心代码如下所示:

def process_request(self, request, spider):
    logger.debug('processing request %s', request)  
    return as_deferred(self._process_request(request, spider))

这里其实就是调用了一个 _process_request 方法,这个方法的返回结果被 as_deferred 方法调用了。

这个 as_deferred 是怎么定义的呢?代码如下:

import asyncio
from twisted.internet.defer import Deferred
​
def as_deferred(f):
    return Deferred.fromFuture(asyncio.ensure_future(f))

这个方法接收的就是一个 asyncio 库的 Future 对象,然后通过 fromFuture 方法转化成了 twisted 里面的 Deferred 对象。这是因为 Scrapy 本身的异步是借助 twisted 实现的,一个个的异步任务对应的就是一个个 Deferred 对象,而 Pyppeteer 又是基于 asyncio 的,它的异步任务是 Future 对象,所以这里我们需要借助 Deferred 的 fromFuture 方法将 Future 转为 Deferred 对象。

另外为了支持这个功能,我们还需要在 Scrapy 中修改 reactor 对象,修改为 AsyncioSelectorReactor,实现如下:

import sys
from twisted.internet.asyncioreactor import AsyncioSelectorReactor
import twisted.internet
​
reactor = AsyncioSelectorReactor(asyncio.get_event_loop())# install AsyncioSelectorReactor
twisted.internet.reactor = reactor
sys.modules['twisted.internet.reactor'] = reactor

这段代码已经在 PyppeteerMiddleware 里面定义好了,在 Scrapy 正式开始爬取之前这段代码就会被执行,将 Scrapy 中的 reactor 修改为 AsyncioSelectorReactor,从而实现 Future 的调度。
接下来我们再来看下 _process_request 方法,实现如下:

async def _process_request(self, request: PyppeteerRequest, spider):
    """
    use pyppeteer to process spider
    :param request:
    :param spider:
    :return:
    """
    options = {
        'headless': self.headless,
        'dumpio': self.dumpio,
        'devtools': self.devtools,
        'args': [
            f'--window-size={self.window_width},{self.window_height}',
        ]
    }
    if self.executable_path: options['executable_path'] = self.executable_path
    if self.disable_extensions: options['args'].append('--disable-extensions')
    if self.hide_scrollbars: options['args'].append('--hide-scrollbars')
    if self.mute_audio: options['args'].append('--mute-audio')
    if self.no_sandbox: options['args'].append('--no-sandbox')
    if self.disable_setuid_sandbox: options['args'].append('--disable-setuid-sandbox')
    if self.disable_gpu: options['args'].append('--disable-gpu')
    
    # set proxy
    proxy = request.proxy
    if not proxy:
        proxy = request.meta.get('proxy')
    if proxy: options['args'].append(f'--proxy-server={proxy}')
    
    logger.debug('set options %s', options)
    
    browser = await launch(options)
    page = await browser.newPage()
    await page.setViewport({'width': self.window_width, 'height': self.window_height})
    
    # set cookies
    if isinstance(request.cookies, dict):
        await page.setCookie(*[
            {'name': k, 'value': v}
            for k, v in request.cookies.items()
        ])
    else:
        await page.setCookie(request.cookies)
    
    # the headers must be set using request interception
    await page.setRequestInterception(True)
    
    @page.on('request')
    async def _handle_interception(pu_request):
        # handle headers
        overrides = {
            'headers': {
                k.decode(): ','.join(map(lambda v: v.decode(), v))
                for k, v in request.headers.items()
            }
        }
        # handle resource types
        _ignore_resource_types = self.ignore_resource_types
        if request.ignore_resource_types is not None:
            _ignore_resource_types = request.ignore_resource_types
        if pu_request.resourceType in _ignore_resource_types:
            await pu_request.abort()
        else:
            await pu_request.continue_(overrides)
    
    timeout = self.download_timeout
    if request.timeout is not None:
        timeout = request.timeout
    
    logger.debug('crawling %s', request.url)
    
    response = None
    try:
        options = {
            'timeout': 1000 * timeout,
            'waitUntil': request.wait_until
        }
        logger.debug('request %s with options %s', request.url, options)
        response = await page.goto(
            request.url,
            options=options
        )
    except (PageError, TimeoutError):
        logger.error('error rendering url %s using pyppeteer', request.url)
        await page.close()
        await browser.close()
        return self._retry(request, 504, spider)
    
    if request.wait_for:
        try:
            logger.debug('waiting for %s finished', request.wait_for)
            await page.waitFor(request.wait_for)
        except TimeoutError:
            logger.error('error waiting for %s of %s', request.wait_for, request.url)
            await page.close()
            await browser.close()
            return self._retry(request, 504, spider)
    
    # evaluate script
    if request.script:
        logger.debug('evaluating %s', request.script)
        await page.evaluate(request.script)
    
    # sleep
    if request.sleep is not None:
        logger.debug('sleep for %ss', request.sleep)
        await asyncio.sleep(request.sleep)
    
    content = await page.content()
    body = str.encode(content)
    
    # close page and browser
    logger.debug('close pyppeteer')
    await page.close()
    await browser.close()
    
    if not response:
        logger.error('get null response by pyppeteer of url %s', request.url)
    
    # Necessary to bypass the compression middleware (?)
    response.headers.pop('content-encoding', None)
    response.headers.pop('Content-Encoding', None)
    
    return HtmlResponse(
        page.url,
        status=response.status,
        headers=response.headers,
        body=body,
        encoding='utf-8',
        request=request
    )

代码内容比较多,我们慢慢来说。

首先最开始的部分是定义 Pyppeteer 的一些启动参数:

options = {
    'headless': self.headless,
    'dumpio': self.dumpio,
    'devtools': self.devtools,
    'args': [
        f'--window-size={self.window_width},{self.window_height}',
    ]
}
if self.executable_path: options['executable_path'] = self.executable_path
if self.disable_extensions: options['args'].append('--disable-extensions')
if self.hide_scrollbars: options['args'].append('--hide-scrollbars')
if self.mute_audio: options['args'].append('--mute-audio')
if self.no_sandbox: options['args'].append('--no-sandbox')
if self.disable_setuid_sandbox: options['args'].append('--disable-setuid-sandbox')
if self.disable_gpu: options['args'].append('--disable-gpu')

这些参数来自 from_crawler 里面读取项目 settings 的内容,如配置 Pyppeteer 对应浏览器的无头模式、窗口大小、是否隐藏滚动条、是否弃用沙箱,等等。

紧接着就是利用 options 来启动 Pyppeteer:

browser = await launch(options)
page = await browser.newPage()
await page.setViewport({'width': self.window_width, 'height': self.window_height})

这里启动了 Pyppeteer 对应的浏览器,将其赋值为 browser,然后新建了一个选项卡,赋值为 page,然后通过 setViewport 方法设定了窗口的宽高。

接下来就是对一些 Cookies 进行处理,如果 Request 带有 Cookies 的话会被赋值到 Pyppeteer 中:

# set cookies
if isinstance(request.cookies, dict):
    await page.setCookie(*[
        {'name': k, 'value': v}
        for k, v in request.cookies.items()
    ])
else:
    await page.setCookie(request.cookies)

再然后关键的步骤就是进行页面的加载了:

try:
    options = {
        'timeout': 1000 * timeout,
        'waitUntil': request.wait_until
    }
    logger.debug('request %s with options %s', request.url, options)
    response = await page.goto(
        request.url,
        options=options
    )
except (PageError, TimeoutError):
    logger.error('error rendering url %s using pyppeteer', request.url)
    await page.close()
    await browser.close()
    return self._retry(request, 504, spider)

这里我们首先制定了加载超时时间 timeout 还有要等待完成的事件 waitUntil,接着调用 page 的 goto 方法访问对应的页面,同时进行了异常检测,如果发生错误就关闭浏览器并重新发起一次重试请求。

在页面加载出来之后,我们还需要判定我们期望的结果是不是加载出来了,所以这里又增加了 waitFor 的调用:

if request.wait_for:
    try:
        logger.debug('waiting for %s finished', request.wait_for)
        await page.waitFor(request.wait_for)
    except TimeoutError:
        logger.error('error waiting for %s of %s', request.wait_for, request.url)
        await page.close()
        await browser.close()
        return self._retry(request, 504, spider)

这里 request 有个 wait_for 属性,就可以定义想要加载的节点的选择器,如 .item .name 等,这样如果页面在规定时间内加载出来就会继续向下执行,否则就会触发 TimeoutError 并被捕获,关闭浏览器并重新发起一次重试请求。

等想要的结果加载出来之后,我们还可以执行一些自定义的 JavaScript 代码完成我们想要自定义的功能:

# evaluate script
if request.script:
    logger.debug('evaluating %s', request.script)
    await page.evaluate(request.script)

最后关键的一步就是将当前页面的源代码打印出来,然后构造一个 HtmlResponse 返回即可:

content = await page.content()
body = str.encode(content)# close page and browser
logger.debug('close pyppeteer')
await page.close()
await browser.close()if not response:
    logger.error('get null response by pyppeteer of url %s', request.url)# Necessary to bypass the compression middleware (?)
response.headers.pop('content-encoding', None)
response.headers.pop('Content-Encoding', None)return HtmlResponse(
    page.url,
    status=response.status,
    headers=response.headers,
    body=body,
    encoding='utf-8',
    request=request
)

所以,如果代码可以执行到最后,返回到就是一个 Response 对象,这个 Resposne 对象的 body 就是 Pyppeteer 渲染页面后的结果,因此这个 Response 对象再传给 Spider 解析,就是 JavaScript 渲染后的页面结果了。

这样我们就通过 Downloader Middleware 通过对接 Pyppeteer 完成 JavaScript 动态渲染页面的抓取了。

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

第46讲:遇到动态页面怎么办?详解渲染页面爬取 的相关文章

  • 【python爬虫】14.Scrapy框架讲解

    文章目录 前言 Scrapy是什么 Scrapy的结构 Scrapy的工作原理 Scrapy的用法 明确目标与分析过程 代码实现 创建项目 代码实现 编辑爬虫 代码实现 定义数据 代码实操 设置 代码实操 运行 复习 前言 前两关 我们学习
  • 【python爬虫】7.爬到的数据存到哪里?

    文章目录 前言 存储数据的方式 存储数据的基础知识 基础知识 Excel写入与读取 基础知识 csv写入与读取 项目 存储周杰伦的歌曲信息 复习 前言 上一关我们以QQ音乐为例 主要学习了如何带参数地请求数据 get请求 和Request
  • [python爬虫] 招聘信息定时系统 (一).BeautifulSoup爬取信息并存储MySQL

    这系列文章主要讲述 如何通过Python爬取招聘信息 且爬取的日期为当前天的 同时将爬取的内容保存到数据库中 然后制作定时系统每天执行爬取 最后是Python调用相关库发送短信到手机 最近研究了数据库的定时计划备份 联系爬虫简单做了这个实验
  • python爬取美女图片

    需求 最近对python爬虫感兴趣 于是也依葫芦画瓢试着用爬虫爬取之前喜欢的网站上的美女图片 网站 http www mm131 com xinggan 其中每一套图都是一张一个页面 存一套图如果是手动得点翻几十个页面 但现在用爬虫的话 就
  • 爬取在线论坛帖子:使用 Python 获取帖子及评论

    在这篇博客中 我们将学习如何使用 Python 编写一个网络爬虫 从一个在线论坛 例如 Reddit 中获取帖子及其评论 我们将使用 requests 和 BeautifulSoup 库来实现这个功能 文章将包括以下内容 目录 1 爬虫的基
  • 【安装教程】夜神模拟器+抓包工具mitmproxy

    夜神模拟器官网下载 应用商城搜索 小红书 下载软件即可 python 安装 mitmproxy 1 安装Microsoft Visual buildtools 链接 https pan baidu com s 1GyLNOOydBoOtNB
  • 如何更高效的提高CSDN浏览量 - 提升博客的曝光度

    前言 CSDN作为中国最大的IT技术社区 对于技术人员而言 拥有高浏览量的博客是提升个人知名度和影响力的关键 本文将介绍一个名为 CSDN Browsing Plus 的工具 通过它 我们可以更高级地增长CSDN的浏览量 提升博客的曝光度
  • 基于Python+Pyecharts+爬虫实现的对全球疫情新增患者可视化分析

    文章目录 前言 1 爬取网站获取全球各国新冠新增人数 1 1挑选网站进行网页源码分析 1 2对该网站采用requests库进行网络爬取 1 3将返回的字典添加到刚才所建立的空列表当中 2 对所得数据进行可视化分析 2 1采用pyechart
  • 用Python进行网络爬虫和数据分析的初次尝试(一)

    某天突然起了兴致 想知道国内每个成员有多少粉 但不知道应该怎么做 各个应援会论坛的用户数 很多粉也去其它成岩的应援论坛 不靠谱 各个贴吧会员数 这只能说明某个成员是否出名 并且也有和应援论坛相同的弊端 最好的方法是在一个中立 无成员倾向的
  • Scrapy实战案例--抓取股票数据并存入SQL数据库(JS逆向)

    目标网址 http webapi cninfo com cn marketDataZhishu 之前在这篇文章里面对该网站的JS进行了一个逆向的解析 JS逆向解析案例 接下来我们来创建一个Scrapy项目来爬取某潮的数据并保存在数据库中 过
  • 网络爬虫 - 6 JsonPath的使用方法与爬取案例

    1 json数据解析 1 json概念 JSON 是存储和交换文本信息的语法 类似 XML JSON 比 XML 更小 更快 更易解析 JSON 是纯文本 JSON 具有 自我描述性 人类可读 JSON 具有层级结构 值中存在值 JSON
  • Python selenium webdriver 基本使用

    系列文章目录 selenium webdriver 的常用示例 文章目录 系列文章目录 selenium webdriver 的常用示例 前言 一 Pip安装 创建Bowser对象 1 Pip install selenium 2 创建Bo
  • 爬取技术博客文章:从技术博客获取最新文章

    目录 1 爬取技术博客文章简介 2 准备工作 3 分析技术博客网站结构
  • 大数据采集概述

    文章目录 大数据采集概述 1 互联网大数据与采集 1 1互联网大数据来源 1 社交媒体 2 社交网络 3 百科知识库 4 新闻网站 5 评论信息 6 位置型信息 1 2 互联网大数据的特征 1 大数据类型和语义更加丰富 2 数据的规范化程度
  • Python爬虫学习笔记(三)————urllib

    目录 1 使用urllib来获取百度首页的源码 2 下载网页图片视频 3 总结 1 4 请求对象的定制 解决第一种反爬 5 编解码 1 get请求方式 urllib parse quote 2 get请求方式 urllib parse ur
  • 网络爬虫:URL链接中含{}时,运用format输出的变化特例

    示例 维基百科日本检索 keyword 漫画 https ja wikipedia org w index php title E7 89 B9 E5 88 A5 E6 A4 9C E7 B4 A2 limit 20 offset 0 ns
  • 7种有效安全的网页抓取方法,如何避免被禁止?

    网页抓取是一种从互联网上抓取网页内容的过程 但在网络抓取种相信您也经常遇到障碍 尤其是做跨境业务的 在抓取国外的网站时更有难度 但我们站在您的立场上 提供七种有效的方法来进行网页抓取而不被阻止 最大限度地降低网站禁令的风险 并帮助您应对相关
  • 9.用python写网络爬虫,完结

    前言 这是python网络爬虫的最后一篇给大家做个总结 且看且珍惜把 截止到目前 前几章本书介绍的爬虫技术都应用于一个定制网站 这样可以帮助我们更加专注于学习特定技巧 而在本章中 我们将分析几个真实网站 来看看这些技巧是如何应用的 首先我们
  • 程序员教你如何用Python爬取付费小说

    小说相信大家都爱看吧一章接一章具有极大的吸引力 看了还想看 当然付费小说价格也不便宜 看到一半突然收费 猝不及防 在我们程序员这里 收费是不存在的 万物皆可爬 什么是网络爬虫 网络爬虫 又被称为网页蜘蛛 网络机器人 在FOAF社区中间 更经
  • 淘宝商品类目接口API:获取淘宝商品分类类目信息

    cat get 获得淘宝分类详情 响应参数 名称 类型 必须 示例值 描述 info Mix 0 cid 16 parent cid 0 name 其他女装 is parent true status normal sort order 0

随机推荐

  • 什么是服务器信息怎么看,怎么查看服务器信息

    怎么查看服务器信息 内容精选 换一换 在您申请了云耀云服务器后 可以通过管理控制台查看和管理您的云耀云服务器 本节介绍如何查看云耀云服务器的详细配置 包括云耀云服务器名称 镜像信息 系统盘 数据盘 安全组 弹性公网IP等信息 登录管理控制台
  • 网盘服务器安装监控系统,服务器监控程序一键安装

    服务器监控程序一键安装 内容精选 换一换 依照配置并导入样例工程中导入和修改样例后 即可在开发环境中 右击 JDBCExample java 选择 Run JDBCExample main 运行对应的应用程序工程 使用Windows访问MR
  • 互联网公司常见性能测试(压测)面试题

    一 性能测试流程 1 首先制定性能测试计划 确定各项指标的目标 期望 2 申请压力机 3 制定性能测试方案 4 执行脚本 如用jmeter命令执行jmx文件 监控数据 zabbix CAT 5 分析数据 并出性能测试报告 二 性能测试关键指
  • Pycharm和Anaconda的关系

    Pycharm和Anaconda的关系 学习记录 知识点输出有风险 相信需谨慎 1 python 所存在的问题两个 第一个 自身缺少numpy matplotlib scipy scikit learn 等一系列包 需要安装pip来导入这些
  • STM32F103RC通过DHT11获取温湿度

    文章目录 bsp dht1 c bsp dht1 h 例子下载 bsp dht1 c file bsp TimBase c author stylle version V1 0 date 2021 xx xx brief DTH11温湿度获
  • Android Studio的NDK的配置

    有时会遇到NDK的配置错误 NDK配置如下 最好不要选择最新版本 我看网上攻略大多是使用21 0 6113669这个版本
  • git 撤回 (git版本回退处理)

    项目中 我们会遇到 提交的项目代码有问题 需要执行撤回命令 但是发现撤回之后还是会运行失败 下边是一个好方法 亲测比 git reset hard 版本号 有效 下面我们详细解说一下 一 已提交 没有push 回滚 当我们本地已经 执行了g
  • 【记关于github应用认证重定向到localhost的疑问】

    要做一个关于github 的OAuth第三方登录 在配置重定向url的时候填写的是本地的测试端口localhos 8080 然后登录认证后可以重定向到本地接口 关于这个重定向我就不理解为啥它可以知道我的IP地址 然后搜索发现这个重定向是告诉
  • JAVA jdk1.8安装图文解说

    对于 jdk 的安装 网上有很多种图文解说 但是老鸟发现它们大都不严谨 非常不适合小白 本节课 老鸟就给大家做个小白教程 无论你多么菜 你一定可以安装上 否则你加我微信 我给你打五毛钱 立帖为证 jdk 有很多版本 我们应该安装哪个呢 如果
  • Python单链表

    用Python写了一个单链表 具有和Python的列表list相似的一些函数 Single link list class Node def init self item self elem item self next None clas
  • php的socket通信以及出现的错误,php的Socket通信以及出现的错误

    php的Socket通信以及出现的错误 flag 1 do conn socket socket accept sock msg Send Message Hello World if socket write conn socket ms
  • grep正则表达式后面的单引号和双引号的区别?

    单引号 可以说是所见即所得 即将单引号内的内容原样输出 或者描述为单引号里面看到的是什么就会输出什么 单引号 是全引用 被单引号括起的内容不管是常量还是变量者不会发生替换 双引号 把双引号内的内容输出出来 如果内容中有命令 变量等 会先把变
  • 【华为机试在线训练】Day 6

    题目描述 定义一个二维数组N M 其中2 lt N lt 10 2 lt M lt 10 如5 5数组下所示 int maze 5 5 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 它表
  • 建议收藏:不能不刷的100道数字IC笔/面试题!

    一 IC设计流程及相应EDA开发工具 前端设计 逻辑设计 1 规格制定 根据客户需求 具体的功能和性能要求 制定芯片规格Spec 2 详细设计 设计方案 具体实现架构 模块划分 3 HDL编码 将实际的硬件电路功能通过HDL语言描述出来 形
  • WebRTC带宽估计

    整体架构 上面这张图是一个比较老的架构图 但是也基本能说明整体架构 早期webrtc版本带宽估计是放到接收端处理 目前最新版本带宽估计放到了发送端 但是接收端计算得到的带宽并没有废弃 而是通过rtcp remb反馈给发送端 在发送端带宽估计
  • 锁相环技术,单边带信号,信号的调制

    什么是锁相环技术 用在接收机中 因为在相干解调的时候 需要接收机产生一个和发射机同频同相的载波频率 这时候就要对发射机处的载波频率进行精确的追踪 锁相环技术就是这样精准跟踪载波频率的一种技术 锁相环 PLL 是一种数字信号处理技术 用于将输
  • html5实现坐标旋转的方法,HTML5 Canvas实现平移/放缩/旋转deom示例(附截图)

    HTML5 Canvas中提供了实现图形平移 旋转 放缩的API 平移 translate 平移坐标translate x y 意思是把 0 0 坐标平移到 x y 原来的 0 0 坐标则变成 x y 图示如下 任何原来的坐标点p ox o
  • vue脚手架项目使用element-ui

    1 通过脚手架创建一个项目 2 在vue脚手架项目中安装elementui npm i element ui S 使用elementui 在mian js中全局引入element ui 2 配置路由router 3 按需导入我们需要的组件
  • 国务院关于积极推进“互联网+”行动的指导意见

    国务院关于积极推进 互联网 行动的指导意见 国发 2015 40号 各省 自治区 直辖市人民政府 国务院各部委 各直属机构 互联网 是把互联网的创新成果与经济社会各领域深度融合 推动技术进步 效率提升和组织变革 提升实体经济创新力和生产力
  • 第46讲:遇到动态页面怎么办?详解渲染页面爬取

    前面我们已经介绍了 Scrapy 的一些常见用法 包括服务端渲染页面的抓取和 API 的抓取 Scrapy 发起 Request 之后 返回的 Response 里面就包含了想要的结果 但是现在越来越多的网页都已经演变为 SPA 页面 其页