【问题标题】:Scrapy return Base64 of Image Url after 10 imagesScrapy在10张图片后返回Image Url的Base64
【发布时间】:2019-03-11 15:00:55
【问题描述】:

我正在尝试使用 scrapy 来抓取数据。我已经根据需要获得了文本数据。但是当我尝试废弃图像 src 时,它会在开始时返回我确切的 url,并在一些记录后返回

"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="

这是我的蜘蛛代码

import scrapy
class CoinmarketcapSpider(scrapy.Spider):
    name = 'coinmarketcap'
    allowed_domains = ['coinmarketcap.com']
    start_urls = ['https://coinmarketcap.com/2']
    def parse(self, response):
        cointable=response.css('table#currencies').xpath('//tbody/tr')
        for coins in cointable:
            name=coins.css('a.currency-name-container::text').extract_first().strip()
            logo=coins.css('img.logo-sprite::attr(src)').extract()
            symbol=coins.css('span.currency-symbol').xpath('.//a/text()').extract_first().strip()
            market_cap=coins.css('.market-cap').xpath('text()').extract_first().strip()
            yield {
                'Name':name,
                'image_urls':logo,
                'symbol':symbol,
                'market_cap':market_cap
            }
        print response

这里有 ImgLogo url 的输出 json 文件

[ {"coinName": ["Bitcoin"], "symbol": ["BTC"], "imgLogo": ["https://s2.coinmarketcap.com/static/img/coins/16x16/1.png"]}, {“coinName”:[“以太坊”],“符号”:[“ETH”],“imgLogo”: ["https://s2.coinmarketcap.com/static/img/coins/16x16/1027.png"]}, {“coinName”:[“XRP”],“符号”:[“XRP”],“imgLogo”: ["https://s2.coinmarketcap.com/static/img/coins/16x16/52.png"]}, {“coinName”:[“比特币现金”],“符号”:[“BCH”],“imgLogo”: ["https://s2.coinmarketcap.com/static/img/coins/16x16/1831.png"]}, {“coinName”:[“EOS”],“符号”:[“EOS”],“imgLogo”: ["https://s2.coinmarketcap.com/static/img/coins/16x16/1765.png"]}, {“coinName”:[“Stellar”],“符号”:[“XLM”],“imgLogo”: ["https://s2.coinmarketcap.com/static/img/coins/16x16/512.png"]}, {"coinName": ["Litecoin"], "symbol": ["LTC"], "imgLogo": ["https://s2.coinmarketcap.com/static/img/coins/16x16/2.png"]}, {"coinName": ["Tether"], "symbol": ["USDT"], "imgLogo": ["https://s2.coinmarketcap.com/static/img/coins/16x16/825.png"]}, {“coinName”:[“Cardano”],“符号”:[“ADA”],“imgLogo”: ["https://s2.coinmarketcap.com/static/img/coins/16x16/2010.png"]}, {“coinName”:[“Monero”],“符号”:[“XMR”],“imgLogo”: ["https://s2.coinmarketcap.com/static/img/coins/16x16/328.png"]}, {“coinName”:[“IOTA”],“符号”:[“MIOTA”],“imgLogo”: ["数据:图像/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAAAAAAAAAAICTAEAOw=="]}, {“coinName”:[“TRON”],“符号”:[“TRX”],“imgLogo”: ["数据:图像/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAAAAAAAAAAICTAEAOw=="]}, {"coinName": ["Dash"], "symbol": ["DASH"], "imgLogo": ["data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="]}]

这是我的 Items.py 代码

import scrapy
class CmindexItem(scrapy.Item):
    # define the fields for your item here like:
     image_urls = scrapy.Field()

这是我的 piplines.py 代码,用于下载图像并将它们保存在我的图像目录中

import scrapy
from scrapy.pipelines.images import ImagesPipeline
from scrapy.exceptions import DropItem


class CmindexPipeline(ImagesPipeline):
    def get_media_requests(self, item, info):
        for image_url in item['image_urls']:
            yield scrapy.Request(image_url)

    def item_completed(self, results, item, info):
        image_paths = [x['path'] for ok, x in results if ok]
        if not image_paths:
            raise DropItem("Item contains no images")
        item['image_paths'] = image_paths
        return item

这是我的 settings.py 代码

BOT_NAME = 'cmindex'

SPIDER_MODULES = ['cmindex.spiders']
NEWSPIDER_MODULE = 'cmindex.spiders'
USER_AGENT = 'cmindex (+http://www.cmindex.com)'
# Obey robots.txt rules
ROBOTSTXT_OBEY = True
ITEM_PIPELINES = {'cmindex.pipelines.CmindexPipeline': 1}
IMAGES_STORE ='E:\WorkPlace\cmindex\cmindex\img'
DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
    'scrapy_fake_useragent.middleware.RandomUserAgentMiddleware': 400,
}

我添加了假用户代理,并且还添加了请求延迟,但这并没有影响我的最终结果。所以如果有人有想法请分享。谢谢

【问题讨论】:

    标签: python-2.7 xpath scrapy


    【解决方案1】:

    请从您的 settings.py 中删除以下内容

    USER_AGENT = 'cmindex (+http://www.cmindex.com)'
    DOWNLOADER_MIDDLEWARES = {
        'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
        'scrapy_fake_useragent.middleware.RandomUserAgentMiddleware': 400,
    }
    

    也取消关注 Robotstxt

    ROBOTSTXT_OBEY = False
    

    请在您的蜘蛛文件中进行以下更改。 查看 coinmarketcap 的源码后发现,经过 10 行 Image 的 Src 是二进制的,那么简单然后获取 Image 的 Data-src 而不是 src。

    import scrapy
    class CoinmarketcapSpider(scrapy.Spider):
    name = 'coinmarketcap'
    allowed_domains = ['coinmarketcap.com']
    start_urls = ['https://coinmarketcap.com/']
    def parse(self, response):
    
        cointable=response.css('table#currencies').xpath('//tbody/tr')
        for coins in cointable:
            name=coins.css('a.currency-name-container::text').extract_first().strip()
            logoData = coins.css('img.logo-sprite::attr(data-src)').extract()
            logoSrc=coins.css('img.logo-sprite::attr(src)').extract()
            if(logoData==[]):
                logo=logoSrc
            else:
                logo=logoData
    
    
    
            symbol=coins.css('span.currency-symbol').xpath('.//a/text()').extract_first().strip()
            market_cap=coins.css('.market-cap').xpath('text()').extract_first().strip()
            yield {
                'Name':name,
                'image_urls':logo,
                'symbol':symbol,
                'market_cap':market_cap,
            }
        print(response)
    

    【讨论】:

    • 这就是我所缺少的。谢谢你的时间 。快乐编码
    【解决方案2】:

    首先,这是您将从响应中获得的相关原始 html。

    前 10 行中硬币的 HTML sn-p

    10
    </td>
    <td class="no-wrap currency-name" data-sort="Tether">
    <img src="https://s2.coinmarketcap.com/static/img/coins/16x16/825.png" class="logo-sprite" alt="Tether" height="16" width="16">
    

    第 10 行之后的硬币的 HTML sn-p

    11
    </td>
    <td class="no-wrap currency-name" data-sort="TRON">
    <img data-src="https://s2.coinmarketcap.com/static/img/coins/16x16/1958.png" class="logo-sprite lazyload" alt="TRON" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" height="16" width="16">
    

    基本上,服务器发送两种不同格式的数据。一个用于第 1-10 行,另一个用于第 10 行。与第 1-10 行一样,获取 src 属性,但从第 11 行开始,您将 src 属性作为 base64 和 data-src 属性。但是我可以看到 data-src 属性终于被应用到浏览器端的 src 属性上。

    下一个问题应该是它为什么这样做?

    我认为这里的目的是尽可能快地显示数据,类似于渐进式加载。我无法推测该方案的有效性,可能您的页面大小也为 10 以某种显示格式。

    所以基本上第 1-10 行具有用于浏览器渲染的最终 html,但从第 11 行开始,Java 脚本就会发生魔法。现在 java 脚本已被缩小和压缩,但我假设以下 sn-ps(使用图像以获得更好的表示)正在将 data-src 属性的值传输到 src 属性。

    说了这么多,我认为废弃的安全方法是使用

    1. 使用data-src的属性值
    2. 如果 data-src 不可用,请使用 src 属性。

    这是 scrappy 将看到的源代码或 html。

    第 11 行及更多行的 src 以及 "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAAAAAAEAAAICTAEAOw==" 是一种放置的持有人图像,我认为它们都是相同的,并且看起来是 1x1 像素。

    【讨论】:

    • data-src 不适用于初始图像,它返回空结果,这就是我使用 src 的原因。
    • 是的,如果它不可用,请使用 src。这样,您一定会始终如一地获得正确的网址。我刚刚格式化了我的答案,基本上就是这样。
    • 抱歉,src 和 data-src 的值相同
    • 不,在 scrappy 将获取的原始 html 中(或者在 chrome 或 firefox 中查看源代码,您可以执行 wget 或 curl),对于 row1-10,您将具有带有 url 的 src 属性。从第 11 行开始,您将拥有带有 url 的 data-src。所以基本上如果你使用 data-src 并且如果不存在 src 你应该没问题。
    • 请看,编辑后的答案显示了源 html,scrapy 会看到。
    【解决方案3】:

    data:image/gif;base64,R0l... 以 base64 编码的完整图像。

    查看 data-uris 上的 mozillas 文档:

    数据 URL,以 data: 为前缀的 URL 方案,允许内容创建者将小文件内嵌在文档中。

    数据 URL 由四部分组成:前缀 (data:)、指示数据类型的 MIME 类型、可选的 base64 标记(如果非文本)和数据本身:

    data:[<mediatype>][;base64],<data>
    

    在您的情况下,媒体类型为:image/gif,编码为base64,您的实际图像为R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==

    你可以用python的base64包解码:

    with open('foo.gif', 'wb') as f:
        f.write(base64.b64decode("R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-04
      • 1970-01-01
      • 1970-01-01
      • 2018-05-08
      • 1970-01-01
      • 2016-06-24
      • 1970-01-01
      • 2018-08-15
      相关资源
      最近更新 更多