<?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>抖音 on heyaohua's Blog</title><link>https://blog.heyaohua.com/tags/%E6%8A%96%E9%9F%B3/</link><description>Recent content in 抖音 on heyaohua's Blog</description><image><title>heyaohua's Blog</title><url>https://blog.heyaohua.com/og-image.png</url><link>https://blog.heyaohua.com/og-image.png</link></image><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Mon, 15 Jan 2024 16:30:00 +0800</lastBuildDate><atom:link href="https://blog.heyaohua.com/tags/%E6%8A%96%E9%9F%B3/index.xml" rel="self" type="application/rss+xml"/><item><title>抖音长截图服务使用说明</title><link>https://blog.heyaohua.com/posts/2024/01/douyin-screenshot-service/</link><pubDate>Mon, 15 Jan 2024 16:30:00 +0800</pubDate><guid>https://blog.heyaohua.com/posts/2024/01/douyin-screenshot-service/</guid><description>本文介绍基于 Playwright 封装的抖音长截图服务，涵盖能力范围、接口设计、使用范例以及性能调优建议，便于快速集成到现有业务系统中。</description><content:encoded><![CDATA[<p>本文介绍基于 Playwright 封装的抖音长截图服务，涵盖能力范围、接口设计、使用范例以及性能调优建议，便于快速集成到现有业务系统中。</p>
<h2 id="服务概述">服务概述</h2>
<p>核心功能已经封装在 <code>app/services/playwright_service.py</code> 中，经过大量测试验证，推荐使用的默认参数如下：</p>
<ul>
<li>滚动距离：1000 px</li>
<li>底部裁剪：300 px</li>
<li>平均截图数量：4–5 张</li>
<li>平均文件大小：2–4 MB</li>
</ul>
<blockquote>
<p>GitHub 仓库：<a href="https://github.com/heyaohua/douyin_screenshot_service">https://github.com/heyaohua/douyin_screenshot_service</a></p>
</blockquote>
<h2 id="核心能力">核心能力</h2>
<ul>
<li><strong>移动端模拟</strong>：完整模拟 iPhone 设备视口与 UA</li>
<li><strong>智能滚动</strong>：自动识别内部滚动容器并控制节奏</li>
<li><strong>懒加载处理</strong>：触发页面动态内容渲染</li>
<li><strong>图像拼接</strong>：裁剪重叠区域，生成无缝长图</li>
<li><strong>错误处理</strong>：封装异常重试、日志与超时机制</li>
</ul>
<h3 id="主要接口">主要接口</h3>
<h4 id="take_long_screenshoturl-output_dirscreenshots"><code>take_long_screenshot(url, output_dir=&quot;screenshots&quot;)</code></h4>
<ul>
<li><code>url</code>：待截图抖音页面 URL</li>
<li><code>output_dir</code>：输出目录（默认 <code>screenshots</code>）</li>
</ul>
<p>返回值示例：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;success&#34;</span>: True,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;output_path&#34;</span>: <span style="color:#f1fa8c">&#34;screenshots/douyin_long_screenshot_20250916_135333.png&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;screenshot_count&#34;</span>: <span style="color:#bd93f9">4</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;total_height&#34;</span>: <span style="color:#bd93f9">9228</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;file_size&#34;</span>: <span style="color:#bd93f9">2764800</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;original_url&#34;</span>: <span style="color:#f1fa8c">&#34;https://v.douyin.com/...&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;current_url&#34;</span>: <span style="color:#f1fa8c">&#34;https://haohuo.jinritemai.com/...&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;title&#34;</span>: <span style="color:#f1fa8c">&#34;页面标题&#34;</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h2 id="http-api-设计">HTTP API 设计</h2>
<h3 id="长截图接口">长截图接口</h3>
<ul>
<li><strong>请求</strong>：<code>POST /douyin/long-screenshot</code></li>
<li><strong>请求体</strong>：</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&#34;url&#34;</span>: <span style="color:#f1fa8c">&#34;https://v.douyin.com/Zdo3P7Zv51o/&#34;</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><ul>
<li><strong>响应</strong>：</li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&#34;message&#34;</span>: <span style="color:#f1fa8c">&#34;长截图完成&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&#34;data&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;success&#34;</span>: <span style="color:#ff79c6">true</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;output_path&#34;</span>: <span style="color:#f1fa8c">&#34;screenshots/douyin_long_screenshot_20250916_135333.png&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;screenshot_count&#34;</span>: <span style="color:#bd93f9">4</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;total_height&#34;</span>: <span style="color:#bd93f9">9228</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">&#34;file_size&#34;</span>: <span style="color:#bd93f9">2764800</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h3 id="测试接口">测试接口</h3>
<ul>
<li><strong>请求</strong>：<code>POST /douyin/test-long-screenshot</code></li>
<li><strong>说明</strong>：使用预设 URL 触发一次完整流程，便于巡检。</li>
</ul>
<h2 id="使用示例">使用示例</h2>
<h3 id="服务内调用">服务内调用</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ff79c6">from</span> app.services.playwright_service <span style="color:#ff79c6">import</span> playwright_service
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">async</span> <span style="color:#ff79c6">def</span> <span style="color:#50fa7b">example</span>():
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">await</span> playwright_service<span style="color:#ff79c6">.</span>initialize()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    result <span style="color:#ff79c6">=</span> <span style="color:#ff79c6">await</span> playwright_service<span style="color:#ff79c6">.</span>take_long_screenshot(
</span></span><span style="display:flex;"><span>        url<span style="color:#ff79c6">=</span><span style="color:#f1fa8c">&#34;https://v.douyin.com/Zdo3P7Zv51o/&#34;</span>,
</span></span><span style="display:flex;"><span>        output_dir<span style="color:#ff79c6">=</span><span style="color:#f1fa8c">&#34;screenshots&#34;</span>
</span></span><span style="display:flex;"><span>    )
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">if</span> result[<span style="color:#f1fa8c">&#34;success&#34;</span>]:
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">print</span>(<span style="color:#f1fa8c">f</span><span style="color:#f1fa8c">&#34;截图完成: </span><span style="color:#f1fa8c">{</span>result[<span style="color:#f1fa8c">&#39;output_path&#39;</span>]<span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">print</span>(<span style="color:#f1fa8c">f</span><span style="color:#f1fa8c">&#34;截图数量: </span><span style="color:#f1fa8c">{</span>result[<span style="color:#f1fa8c">&#39;screenshot_count&#39;</span>]<span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">&#34;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#8be9fd;font-style:italic">print</span>(<span style="color:#f1fa8c">f</span><span style="color:#f1fa8c">&#34;总高度: </span><span style="color:#f1fa8c">{</span>result[<span style="color:#f1fa8c">&#39;total_height&#39;</span>]<span style="color:#f1fa8c">}</span><span style="color:#f1fa8c">px&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">await</span> playwright_service<span style="color:#ff79c6">.</span>close()
</span></span></code></pre></div><h3 id="http-api-调用">HTTP API 调用</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>curl -X POST <span style="color:#f1fa8c">&#34;http://localhost:8000/douyin/long-screenshot&#34;</span> <span style="color:#f1fa8c">\
</span></span></span><span style="display:flex;"><span>     -H <span style="color:#f1fa8c">&#34;Content-Type: application/json&#34;</span> <span style="color:#f1fa8c">\
</span></span></span><span style="display:flex;"><span>     -d <span style="color:#f1fa8c">&#39;{&#34;url&#34;: &#34;https://v.douyin.com/Zdo3P7Zv51o/&#34;}&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>curl -X POST <span style="color:#f1fa8c">&#34;http://localhost:8000/douyin/test-long-screenshot&#34;</span>
</span></span></code></pre></div><h3 id="本地测试脚本">本地测试脚本</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#8be9fd;font-style:italic">cd</span> tests
</span></span><span style="display:flex;"><span>python test_service.py
</span></span></code></pre></div><h2 id="性能指标">性能指标</h2>
<table>
  <thead>
      <tr>
          <th>滚动距离</th>
          <th>截图数量</th>
          <th>平均文件大小</th>
          <th>效率评估</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1000 px</td>
          <td>4–5 张</td>
          <td>2.6–3.7 MB</td>
          <td>⭐⭐⭐⭐⭐ 推荐参数</td>
      </tr>
      <tr>
          <td>900 px</td>
          <td>6 张</td>
          <td>4.6 MB</td>
          <td>⭐⭐⭐⭐</td>
      </tr>
      <tr>
          <td>800 px</td>
          <td>6 张</td>
          <td>4.3 MB</td>
          <td>⭐⭐⭐</td>
      </tr>
      <tr>
          <td>700 px</td>
          <td>7 张</td>
          <td>5.0 MB</td>
          <td>⭐⭐</td>
      </tr>
      <tr>
          <td>600 px</td>
          <td>8 张</td>
          <td>5.7 MB</td>
          <td>⭐</td>
      </tr>
  </tbody>
</table>
<h2 id="目录结构">目录结构</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>app/services/
</span></span><span style="display:flex;"><span>├── playwright_service.py     # 主服务入口
</span></span><span style="display:flex;"><span>│   ├── take_long_screenshot  # 长截图方法
</span></span><span style="display:flex;"><span>│   └── _stitch_screenshots   # 图片拼接方法
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>app/api/
</span></span><span style="display:flex;"><span>├── douyin.py                 # HTTP API 定义
</span></span><span style="display:flex;"><span>│   ├── /long-screenshot      # 长截图接口
</span></span><span style="display:flex;"><span>│   └── /test-long-screenshot # 测试接口
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>tests/
</span></span><span style="display:flex;"><span>├── test_service.py           # 集成测试脚本
</span></span><span style="display:flex;"><span>└── simple_douyin_test.py     # 快速验证脚本
</span></span></code></pre></div><h2 id="运维与实践建议">运维与实践建议</h2>
<ol>
<li><strong>生命周期管理</strong>：调用前需执行 <code>initialize()</code>，结束后务必调用 <code>close()</code> 释放浏览器资源。</li>
<li><strong>目录权限</strong>：确保输出目录具备写权限，并定期清理历史截图。</li>
<li><strong>错误兜底</strong>：检查返回的 <code>success</code> 字段并结合日志定位问题。</li>
<li><strong>并发控制</strong>：视负载设置队列或限流，避免同时创建大量浏览器实例。</li>
<li><strong>监控告警</strong>：建议将成功率、耗时、文件大小等指标纳入监控系统。</li>
</ol>
<h2 id="日志样例">日志样例</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>2025-09-16 13:53:33,832 - INFO - 拼接图片尺寸: 1170 x 9228
</span></span><span style="display:flex;"><span>2025-09-16 13:53:35,160 - INFO - ✅ 成功: True
</span></span><span style="display:flex;"><span>2025-09-16 13:53:35,160 - INFO - 📊 截图数量: 4
</span></span><span style="display:flex;"><span>2025-09-16 13:53:35,160 - INFO - 💾 文件大小: 2.64MB
</span></span></code></pre></div><h2 id="成功案例">成功案例</h2>
<ul>
<li>URL：<code>https://v.douyin.com/Zdo3P7Zv51o/</code></li>
<li>截图数量：4 张</li>
<li>总高度：9228 px</li>
<li>文件大小：2.64 MB</li>
<li>处理时长：约 22 秒</li>
<li>成功率：100%</li>
</ul>
<hr>
<p>如需深入定制或扩展能力，请参考仓库中的完整代码与测试用例。</p>
]]></content:encoded></item></channel></rss>