<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>QueryList - 她和她的猫</title>
    <link>https://her-cat.com/tags/querylist/</link>
    <description>QueryList的文章列表 - 她和她的猫</description>
    <image>
      <title>她和她的猫</title>
      <url>https://her-cat.com/assets/favorite.jpeg</url>
      <link>https://her-cat.com/assets/favorite.jpeg</link>
    </image>
    <generator>Hugo -- 0.148.1</generator>
    <language>zh</language>
    <lastBuildDate>Sat, 08 Sep 2018 23:26:21 +0800</lastBuildDate>
    <atom:link href="https://her-cat.com/tags/querylist/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>使用 QueryList &#43; Redis 下载壁纸</title>
      <link>https://her-cat.com/posts/2018/09/08/use-querylist-redis-to-download-wallpaper/</link>
      <pubDate>Sat, 08 Sep 2018 23:26:21 +0800</pubDate>
      <guid>https://her-cat.com/posts/2018/09/08/use-querylist-redis-to-download-wallpaper/</guid>
      <description>页面分析 打开网站首页，通过审查元素找到详情页面和略缩图的地址（下图红框部分）。详情页面地址： ./wallpaper-6873.html 略缩图地</description>
      <content:encoded><![CDATA[<p>完整代码：https://github.com/her-cat/wallpaper_crawler</p>
<h2 id="页面分析">页面分析</h2>
<ul>
<li>壁纸站地址：http://www.huanse.net/</li>
</ul>
<p>打开网站首页，通过审查元素找到详情页面和略缩图的地址（下图红框部分）。</p>
<ul>
<li>详情页面地址： <code>./wallpaper-6873.html</code></li>
<li>略缩图地址：<code>./uploads/thumb/thumb-6873.jpg</code> <br/></li>
</ul>
<p>可以看到这两个地址中都有 <code>6873</code> 这个数字，先猜测一下这个数字是这张壁纸的id，也就是唯一标识符。</p>
<p><img decoding="async" height="1080" loading="lazy" sizes="(max-width: 768px) 100vw, (max-width: 1024px) 768px, 1024px" src="/posts/2018/09/08/use-querylist-redis-to-download-wallpaper/1.jpeg" srcset="/posts/2018/09/08/use-querylist-redis-to-download-wallpaper/1_hu_de4020d15647f4e6.jpeg 384w, /posts/2018/09/08/use-querylist-redis-to-download-wallpaper/1_hu_2561d66d943ecb6a.jpeg 768w, /posts/2018/09/08/use-querylist-redis-to-download-wallpaper/1_hu_4054a40ac895280e.jpeg 1024w, /posts/2018/09/08/use-querylist-redis-to-download-wallpaper/1_hu_97e73b82f1cae954.jpeg 1536w, /posts/2018/09/08/use-querylist-redis-to-download-wallpaper/1.jpeg 2137w" style="max-width: 100%; height: auto; aspect-ratio: 1.9787;" width="2137"></p>
<p>为了验证猜测是否正确，打开详情页面对 <code>点击按钮下载</code> 右键审查元素，就看到下载壁纸的url。</p>
<p><img decoding="async" height="970" loading="lazy" sizes="(max-width: 768px) 100vw, (max-width: 1024px) 768px, 1024px" src="/posts/2018/09/08/use-querylist-redis-to-download-wallpaper/2.png" srcset="/posts/2018/09/08/use-querylist-redis-to-download-wallpaper/2_hu_a7ba036cf909064b.png 384w, /posts/2018/09/08/use-querylist-redis-to-download-wallpaper/2_hu_796bb902d9fd3f00.png 768w, /posts/2018/09/08/use-querylist-redis-to-download-wallpaper/2_hu_6ed2e2e8bdc2784b.png 1024w, /posts/2018/09/08/use-querylist-redis-to-download-wallpaper/2_hu_30f9be5c1d73ec3a.png 1536w, /posts/2018/09/08/use-querylist-redis-to-download-wallpaper/2.png 2134w" style="max-width: 100%; height: auto; aspect-ratio: 2.2000;" width="2134"></p>
<p>从下载地址中可以看到 <code>wallpaper=6873</code> 这个参数，现在就能确认 <code>6873</code> 是壁纸的id。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">window</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">&#39;./download.php?wallpaper=6873&amp;type=1&#39;</span><span class="p">)</span>
</span></span></code></pre></div><p>也就是说只要知道壁纸的id，就可以得到壁纸的下载地址。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">www</span><span class="o">.</span><span class="n">huanse</span><span class="o">.</span><span class="n">net</span><span class="o">/</span><span class="n">download</span><span class="o">.</span><span class="n">php</span><span class="err">?</span><span class="n">wallpaper</span><span class="o">=</span><span class="p">{</span><span class="err">壁纸</span><span class="n">id</span><span class="p">}</span><span class="o">&amp;</span><span class="n">type</span><span class="o">=</span><span class="mi">1</span>
</span></span></code></pre></div><p>所以爬取的流程就是获取壁纸id，拼接出下载地址，然后下载壁纸。</p>
<h2 id="爬取壁纸id">爬取壁纸id</h2>
<p>壁纸的id在列表页就已经有了，所以我们只需要对列表页进行循环爬取就行了。</p>
<p><img decoding="async" height="1338" loading="lazy" sizes="(max-width: 768px) 100vw, (max-width: 1024px) 768px, 1024px" src="/posts/2018/09/08/use-querylist-redis-to-download-wallpaper/3.png" srcset="/posts/2018/09/08/use-querylist-redis-to-download-wallpaper/3_hu_f558d00f7811dcb0.png 384w, /posts/2018/09/08/use-querylist-redis-to-download-wallpaper/3_hu_8b244a85135a7915.png 768w, /posts/2018/09/08/use-querylist-redis-to-download-wallpaper/3_hu_a1391e47cd56e286.png 1024w" style="max-width: 100%; height: auto; aspect-ratio: 0.7900;" width="1057"></p>
<p>使用到的工具：</p>
<ul>
<li><a href="https://github.com/jae-jae/QueryList">QueryList</a> QueryList具有jQuery一样的DOM操作能力，这样就不用写正则表达式了</li>
<li><a href="https://github.com/nrk/predis">predis</a> php连接redis的操作库，用来保存壁纸id</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">require</span> <span class="s1">&#39;vendor/autoload.php&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">QL\QueryList</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Predis\Client</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 实例化 redis 连接
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Predis\Client</span><span class="p">(</span><span class="s1">&#39;tcp://127.0.0.1:6379&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$page</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">do</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 使用 QueryList 获取 html 网页内容，找到所有 img 标签的 data-echo 属性的值
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nv">$data</span> <span class="o">=</span> <span class="nx">QueryList</span><span class="o">::</span><span class="na">get</span><span class="p">(</span><span class="s2">&#34;http://www.huanse.net/new-</span><span class="si">{</span><span class="nv">$page</span><span class="si">}</span><span class="s2">.html&#34;</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">find</span><span class="p">(</span><span class="s1">&#39;img&#39;</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">attrs</span><span class="p">(</span><span class="s1">&#39;data-echo&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">count</span><span class="p">(</span><span class="nv">$data</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">foreach</span> <span class="p">(</span><span class="nv">$data</span> <span class="k">as</span> <span class="nv">$datum</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="nv">$datum</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="c1">// 通过分割字符串得到壁纸id
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="nv">$wallpaper_id</span> <span class="o">=</span> <span class="nx">explode</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">,</span> <span class="nx">explode</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">,</span> <span class="nv">$datum</span><span class="p">)[</span><span class="mi">1</span><span class="p">])[</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">                <span class="c1">// 将壁纸id push 到 redis 中
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>                <span class="nv">$client</span><span class="o">-&gt;</span><span class="na">lpush</span><span class="p">(</span><span class="s1">&#39;wallpaper_id_queue&#39;</span><span class="p">,</span> <span class="nv">$wallpaper_id</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">echo</span> <span class="s1">&#39;no data. page: &#39;</span> <span class="o">.</span> <span class="nv">$page</span> <span class="o">.</span> <span class="nx">PHP_EOL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$page</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">echo</span> <span class="s1">&#39;now page: &#39;</span> <span class="o">.</span> <span class="nv">$page</span> <span class="o">.</span> <span class="nx">PHP_EOL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span><span class="k">while</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
</span></span></code></pre></div><p>运行截图：
<img decoding="async" height="386" loading="lazy" src="/posts/2018/09/08/use-querylist-redis-to-download-wallpaper/4.png" style="max-width: 100%; height: auto; aspect-ratio: 0.8109;" width="313"></p>
<p>Redis 中保存的壁纸id
<img decoding="async" height="637" loading="lazy" sizes="(max-width: 768px) 100vw, (max-width: 1024px) 768px, 1024px" src="/posts/2018/09/08/use-querylist-redis-to-download-wallpaper/5.png" srcset="/posts/2018/09/08/use-querylist-redis-to-download-wallpaper/5_hu_e19875003ac3e17d.png 384w" style="max-width: 100%; height: auto; aspect-ratio: 1.1570;" width="737"></p>
<h2 id="下载壁纸">下载壁纸</h2>
<p>下载壁纸这一步很简单，只需要从 redis 中不停的取出壁纸id，然后通过下载地址将壁纸下载到本地。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="k">require</span> <span class="s1">&#39;vendor/autoload.php&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">QL\QueryList</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">use</span> <span class="nx">Predis\Client</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$client</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Predis\Client</span><span class="p">(</span><span class="s1">&#39;tcp://127.0.0.1:6379&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">while</span><span class="p">(</span><span class="k">true</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 从 redis 中取出壁纸id
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nv">$wallpaper_id</span> <span class="o">=</span> <span class="nv">$client</span><span class="o">-&gt;</span><span class="na">rpop</span><span class="p">(</span><span class="s1">&#39;wallpaper_id_queue&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="nv">$wallpaper_id</span> <span class="o">==</span> <span class="s1">&#39;nil&#39;</span> <span class="o">||</span> <span class="nv">$wallpaper_id</span> <span class="o">==</span> <span class="s1">&#39;&#39;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 如果壁纸id为空的话就休眠5秒钟
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">echo</span> <span class="s1">&#39;not have wallpaper data, sleep 5 second...&#39;</span> <span class="o">.</span> <span class="nx">PHP_EOL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nx">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">try</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">downloadWallpaper</span><span class="p">(</span><span class="nv">$wallpaper_id</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 验证壁纸是否保存成功
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">if</span> <span class="p">(</span><span class="nx">file_exists</span><span class="p">(</span><span class="s1">&#39;./wallpaper/&#39;</span> <span class="o">.</span> <span class="s1">&#39;wallpaper-&#39;</span> <span class="o">.</span> <span class="nv">$wallpaper_id</span> <span class="o">.</span> <span class="s1">&#39;.jpg&#39;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">echo</span> <span class="s1">&#39;success: &#39;</span> <span class="o">.</span> <span class="nv">$wallpaper_id</span> <span class="o">.</span> <span class="nx">PHP_EOL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">echo</span> <span class="s1">&#39;fail: &#39;</span> <span class="o">.</span> <span class="nv">$wallpaper_id</span> <span class="o">.</span> <span class="nx">PHP_EOL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">Exception</span> <span class="nv">$e</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">echo</span> <span class="s1">&#39;img exception, sleep 1 second...&#39;</span> <span class="o">.</span> <span class="nx">PHP_EOL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nx">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="sd">/**
</span></span></span><span class="line"><span class="cl"><span class="sd"> * 下载壁纸
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @param $wallpaper_id
</span></span></span><span class="line"><span class="cl"><span class="sd"> * @return int
</span></span></span><span class="line"><span class="cl"><span class="sd"> */</span>
</span></span><span class="line"><span class="cl"><span class="k">function</span> <span class="nf">downloadWallpaper</span><span class="p">(</span><span class="nv">$wallpaper_id</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 拼接下载地址
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nv">$download_url</span> <span class="o">=</span> <span class="nv">$url</span> <span class="o">=</span> <span class="s2">&#34;http://www.huanse.net/download.php?wallpaper=</span><span class="si">{</span><span class="nv">$wallpaper_id</span><span class="si">}</span><span class="s2">&amp;type=1&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">set_time_limit</span> <span class="p">(</span><span class="mi">24</span> <span class="o">*</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">60</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$destination_folder</span> <span class="o">=</span> <span class="s1">&#39;./wallpaper/&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">is_dir</span><span class="p">(</span><span class="nv">$destination_folder</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">mkdirs</span><span class="p">(</span><span class="nv">$destination_folder</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$newfname</span> <span class="o">=</span> <span class="nv">$destination_folder</span> <span class="o">.</span> <span class="s1">&#39;wallpaper-&#39;</span> <span class="o">.</span> <span class="nv">$wallpaper_id</span> <span class="o">.</span> <span class="s1">&#39;.jpg&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$file</span> <span class="o">=</span> <span class="nx">fopen</span> <span class="p">(</span><span class="nv">$url</span><span class="p">,</span> <span class="s2">&#34;rb&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nv">$file</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$newf</span> <span class="o">=</span> <span class="nx">fopen</span> <span class="p">(</span><span class="nv">$newfname</span><span class="p">,</span> <span class="s2">&#34;wb&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nv">$newf</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="nx">feof</span><span class="p">(</span><span class="nv">$file</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nx">fwrite</span><span class="p">(</span><span class="nv">$newf</span><span class="p">,</span> <span class="nx">fread</span><span class="p">(</span><span class="nv">$file</span><span class="p">,</span> <span class="mi">1024</span> <span class="o">*</span> <span class="mi">8</span><span class="p">),</span> <span class="mi">1024</span> <span class="o">*</span> <span class="mi">8</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nv">$file</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">fclose</span><span class="p">(</span><span class="nv">$file</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nv">$newf</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">fclose</span><span class="p">(</span><span class="nv">$newf</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>##运行效果
运行截图：
<img alt="运行截图" decoding="async" height="370" loading="lazy" src="/posts/2018/09/08/use-querylist-redis-to-download-wallpaper/6.jpeg" style="max-width: 100%; height: auto; aspect-ratio: 0.8486;" width="314"></p>
<p>保存的壁纸：
<img alt="保存的壁纸：" decoding="async" height="437" loading="lazy" sizes="(max-width: 768px) 100vw, (max-width: 1024px) 768px, 1024px" src="/posts/2018/09/08/use-querylist-redis-to-download-wallpaper/7.jpeg" srcset="/posts/2018/09/08/use-querylist-redis-to-download-wallpaper/7_hu_3c6a6315e7846392.jpeg 384w, /posts/2018/09/08/use-querylist-redis-to-download-wallpaper/7_hu_eef56239eca9beb4.jpeg 768w, /posts/2018/09/08/use-querylist-redis-to-download-wallpaper/7_hu_d5606f67e3a2772.jpeg 1024w" style="max-width: 100%; height: auto; aspect-ratio: 2.6041;" width="1138"></p>
<blockquote>
<p>爬取壁纸id脚本的脚本用一个窗口执行就够了，下载壁纸的脚本可以多开几个窗口运行，提高壁纸下载速度。</p></blockquote>
]]></content:encoded>
    </item><follow_challenge>
      <feedId>58021783493571598</feedId>
      <userId>56882619875632128</userId>
    </follow_challenge>
  </channel>
</rss>
