如何使用生成器抓取页面内容?

How do I scrape page content with a generator?

我有一个博客,每个 post 都有一堆图片和视频。我希望能够用一些关键字标记它们中的每一个,然后根据标记填充一组页面。例如转到 /photos/car/ 将列出所有标记为 car.

的图像

我现在使用一个简单的插件来包含图像和视频,该插件基本上只有渲染功能。我想我可以在那里添加标签。

但是我怎样才能使 Jekyll 'scrape' 我的页面并用图像填充页面?

简短的回答是:这很棘手

但是为什么呢?

{% img cookie-monster.png tag2,tag3 %} 这样的自定义 imgWithTags-tag 液体标签可以做两件事:

  • 渲染 html 标签
  • 存储标签 -> site.taggedImage 变量中的图像关联

由于此标记可用于任何 post、页面或集合文档,因此 site.taggedImage 变量仅在呈现过程后才完整。

渲染过程完成后,我们可以获取 :site, :post_render 挂钩来处理我们的数据并创建标签页面。

但是在这里,我们不能再依赖诸如 {% for p in tagPages %}...{% endfor %} 之类的东西来自动为我们的页面生成 links:渲染完成。

诀窍可以是手动维护一个 link 数据文件,以便能够生成 link 具有像这样的循环 {% for p in site.data.tagPages %}...{% endfor %}

让我们试一试

注意:这仅适用于 Jekyll 版本 3.1.x(不是 3.0.x)

_plugins/imgWithTags-tag.rb

module Jekyll
  class ImgWithTags < Liquid::Tag

    # Custom liquid tag for images with tags
    # syntax : {% img path/to/img.jpg coma, separated, tags %}
    # tags are optionnal
    #
    # This plugin does two things :
    #   it renders html tag <a href='url'><img src='url' /></a>
    #   it stores tags -> images associations in site.config['images-tags']

    Syntax = /^(?<image_src>[^\s]+\.[a-zA-Z0-9]{3,4})\s*(?<tags>[\s\S]+)?$/

    def initialize(tag_name, markup, tokens)
      super
      if markup =~ Syntax then
        @url = 
        @tags = .split(",").collect!{|tag| tag.strip } if !.nil?
      else
        raise "Image Tag can't read this tag. Try {% img path/to/img.jpg [coma, separated, tags] %}."
      end
    end

    def render(context)
      storeImgTags(context) if defined?(@tags) # store datas if we have tags
      site = context.registers[:site]
      imgTag = "<a href='#{ site.baseurl }/assets/#{@url}'><img src='#{ site.baseurl }/assets/#{@url}' /></a>"
    end

    def storeImgTags(context)
      # store tagged images datas in site config under the key site.config['images-tags']
      imagesTags = context.registers[:site].config['images-tags'] || {}

      @tags.each{|tag|
        slug = Utils.slugify(tag) # My tag -> my-tag
        # create a tag.slug entry if it doesn't exist
        imagesTags[slug] = imagesTags[slug] || {'name' => tag, 'images' => [] }
        # add image url in the tag.images array if the url doesn't already exist
        # this avoid duplicates
        imagesTags[slug]['images'] |= [@url.to_s]
      }
      context.registers[:site].config['images-tags'] = imagesTags
    end

  end
end

Liquid::Template.register_tag('img', Jekyll::ImgWithTags)

此时:所有标记图像 link 均已呈现,所有标记->图像关联已存储。

_plugins/hook-site-post-render-imagesTagsPagesGenerator.rb

Jekyll::Hooks.register :site, :post_render do |site, payload|
  puts "++++++ site post_render hook : generating Images Tags pages"
  imagesTags = site.config['images-tags'] # datas stored by img tag
  linksDatas = site.data['imagesTagsLinks'] # tags pages link in data file
  pagesFolder = 'tag'

  imagesTags.each do |slug, datas|

    tagName = datas['name']
    tagImages = datas['images']
    pageDir =  File.join(pagesFolder, slug)

    tagPage = Jekyll::ImageTagPage.new(site, site.source, pageDir, tagName, tagImages)

    # as page rendering has already fired we do it again for our new pages
    tagPage.output = Jekyll::Renderer.new(site, tagPage, payload).run
    tagPage.trigger_hooks(:post_render)
    site.pages << tagPage

    # verbose check to see if we reference every tag url in out data file
    if !linksDatas.key?(tagName) # check if tag is in imagesTagsLinks data file
      puts "Warning ---------> #{tagName} not in data file"
      puts "Add : #{tagName}: #{tagPage.url}"
      puts "in data/imagesTagsLinks.yml"
      puts
    else
      if tagPage.url != linksDatas[tagName] then # check if url is correct in imagesTagsLinks data file
        puts "Warning ---------> incorrect url for '#{tagName}'"
        puts "Replace : #{tagName}: #{linksDatas[tagName]}"
        puts "by      : #{tagName}: #{tagPage.url}"
        puts "in data/imagesTagsLinks.yml"
        puts
      end
    end

  end
  puts "++++++ END site post_render hook"
end

module Jekyll
  class ImageTagPage < Page
    def initialize(site, base, dir, tag, images)
      @site = site
      @base = base
      @dir = dir
      @name = 'index.html'

      self.process(@name)
      self.read_yaml(File.join(base, '_layouts'), 'tag_index.html')
      self.data['tag'] = tag
      self.data['images'] = images
      self.data['title'] = "Images for tag : #{tag}"
    end
  end
end

以及标签布局页面

_layouts/tag_index.html

---
layout: default
---
<h2>{{ page.title }}</h2>
{% for i in page.images %}
  <img src="{{ site.baseurl }}/assets/{{ i }}" alt="Image tagged {{ page.tag }}">
{% endfor %}

至此,生成标签页面的一切就绪。

我们现在可以执行 jekyll build 并查看详细输出,告诉我们要在 _data/imagesTagsLinks.yml

中添加什么

_数据/imagesTagsLinks.yml

tag1: /tag/tag1/
tag2: /tag/tag2/
...

我们现在可以 link 从任何地方通过一个简单的

到我们的标签页
{% for t in site.data.imagesTagsLinks %}
  <li><a href="{{ site.baseurl }}{{ t[1] }}">{{ t[0] }}</a></li>
{% endfor %}

我告诉过你:这很棘手。但它完成了工作。

注意:img 标签可以改进,为什么 figure 标签不行?