<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
>
<channel>
<title><![CDATA[雅洁网]]></title> 
<atom:link href="https://zhangyajie.net/rss.php" rel="self" type="application/rss+xml" />
<description><![CDATA[记下一些值得记住的]]></description>
<link>https://zhangyajie.net/</link>
<language>zh-cn</language>

<item>
    <title>云服务器端口开放的两层逻辑：安全组与宝塔防火墙的区别</title>
    <link>https://zhangyajie.net/?post=7</link>
    <description><![CDATA[<h2>问题的由来</h2>
<p>在云服务器上部署宝塔面板后，很多新手用户会遇到一个看似矛盾的现象：</p>
<ul>
<li>宝塔面板中显示系统防火墙处于关闭状态。</li>
<li>但每次开放新端口时，仍然必须前往云控制台的安全组中添加规则。</li>
<li>如果只在宝塔中操作，端口始终无法访问。</li>
</ul>
<p>这引出一个常见疑问：<strong>宝塔面板的防火墙能否替代云安全组？</strong></p>
<p>答案是：<strong>不能。二者处于不同层级，职责独立，无法互相替代。</strong></p>
<h2>两层防火墙的层级关系</h2>
<p>云服务器的网络访问控制实际上分为两层：</p>
<ol>
<li>
<p><strong>云平台层：安全组（Security Group）</strong><br />
由云服务商（如腾讯云、阿里云）提供，运行在服务器外部的网络层。它在流量到达服务器之前进行过滤，不由服务器操作系统或宝塔面板控制。</p>
</li>
<li>
<p><strong>操作系统层：系统防火墙</strong><br />
运行在服务器内部，常见实现为 firewalld 或 iptables。宝塔面板的“安全”页面管理的正是这一层。它只处理已经通过云平台安全组、到达服务器的流量。</p>
</li>
</ol>
<p>流量进入服务器的实际顺序如下：</p>
<pre><code>用户请求
   ↓
云平台安全组（第一层）
   ↓
服务器操作系统
   ↓
系统防火墙 / 宝塔防火墙（第二层）
   ↓
Web 服务（Nginx / Apache 等）</code></pre>
<h2>为什么宝塔防火墙无法替代安全组</h2>
<p>关键点在于<strong>流量经过的先后顺序</strong>：</p>
<ul>
<li>如果云平台安全组未放行某个端口，流量根本到不了服务器，系统防火墙无论是否放行都无意义。</li>
<li>如果安全组已放行，但系统防火墙开启且未放行该端口，流量仍会被拦截。</li>
<li>只有当两层都放行（或系统防火墙关闭）时，端口才能真正可访问。</li>
</ul>
<p>因此，宝塔面板的防火墙只能控制第二层，对第一层的安全组没有任何操作权限。</p>
<h2>为什么宝塔显示防火墙关闭，反而简化了操作</h2>
<p>当宝塔面板显示系统防火墙未开启时，意味着第二层没有进行拦截。此时只需在腾讯云安全组中放行端口，即可实现访问。</p>
<p>这也是许多用户选择保持系统防火墙关闭的原因：操作路径更短，只需维护一层规则。</p>
<p>但从安全角度看，这种配置缺少纵深防御。一旦安全组规则出现疏漏，服务器将直接暴露。</p>
<h2>推荐的配置方式</h2>
<p>更稳妥的做法是<strong>两层同时启用，并保持规则一致</strong>：</p>
<table>
<thead>
<tr>
<th>层级</th>
<th>管理位置</th>
<th>建议</th>
</tr>
</thead>
<tbody>
<tr>
<td>云平台安全组</td>
<td>云控制台</td>
<td>仅放行必要端口（如 80、443、修改后的面板端口）</td>
</tr>
<tr>
<td>系统防火墙</td>
<td>宝塔面板</td>
<td>同样仅放行上述端口</td>
</tr>
</tbody>
</table>
<p>这样做的好处是形成纵深防御：即使某一层配置出现疏漏，另一层仍能提供保护。</p>
<p>代价是每开放一个新端口，需要在两个位置分别操作，维护成本略高。</p>
<h2>对比总结</h2>
<table>
<thead>
<tr>
<th>维度</th>
<th>云安全组</th>
<th>宝塔防火墙</th>
</tr>
</thead>
<tbody>
<tr>
<td>所在层级</td>
<td>云平台网络层</td>
<td>服务器操作系统内部</td>
</tr>
<tr>
<td>管理入口</td>
<td>云控制台</td>
<td>宝塔面板</td>
</tr>
<tr>
<td>能否互相替代</td>
<td>否</td>
<td>否</td>
</tr>
<tr>
<td>流量经过顺序</td>
<td>先</td>
<td>后</td>
</tr>
<tr>
<td>宝塔能否控制</td>
<td>否</td>
<td>是</td>
</tr>
</tbody>
</table>
<h2>结论</h2>
<ul>
<li>腾讯云安全组与宝塔防火墙是两层独立、职责不同的访问控制机制，不能互相替代。</li>
<li>流量先经过安全组，再经过系统防火墙；任一层未放行，端口均不可访问。</li>
<li>宝塔显示防火墙关闭，仅表示第二层未启用，并不意味着服务器没有防火墙保护。</li>
<li>追求操作简便可只维护安全组；追求安全性建议两层同时启用并保持规则一致。</li>
</ul>
<p>理解这两层的关系，可以避免在端口开放问题上反复排查，也有助于建立更清晰的云服务器安全模型。</p>]]></description>
    <pubDate>Thu, 08 Oct 2026 14:21:55 +0800</pubDate>
    <dc:creator>雅洁</dc:creator>
    <guid>https://zhangyajie.net/?post=7</guid>
</item>
<item>
    <title>Git 新手实战：从零把本地代码上传到 Gitee</title>
    <link>https://zhangyajie.net/?post=5</link>
    <description><![CDATA[<h3>一、前言</h3>
<blockquote>
<p>最近在 GitHub 上看到一个不错的开源项目，想自己改着玩玩，顺便把代码托管到国内的 Gitee 上。作为一个 Git 小白，这一路遇到了不少坑，特此记录成文，希望能帮到同样刚接触 Git 的朋友。</p>
</blockquote>
<hr />
<h3>二、准备工作</h3>
<p>在开始之前，你需要准备好以下三样东西：</p>
<table>
<thead>
<tr>
<th>项目</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>Gitee 账号</td>
<td>去 <a href="https://gitee.com">gitee.com</a> 注册一个</td>
</tr>
<tr>
<td>Git 工具</td>
<td>下载安装 <a href="https://git-scm.com/downloads">Git</a>，安装后右键菜单会有 <code>Git Bash Here</code></td>
</tr>
<tr>
<td>本地代码</td>
<td>准备好你要上传的项目文件夹</td>
</tr>
</tbody>
</table>
<hr />
<h3>三、完整操作步骤</h3>
<h4>第 1 步：在 Gitee 上创建远程仓库</h4>
<ol>
<li>登录 Gitee，点击右上角的 <strong>&quot;+&quot;</strong> 号，选择 <strong>&quot;新建仓库&quot;</strong>。</li>
<li>填写仓库名称（比如 <code>test_myfirst</code>），建议用英文，不要用中文。</li>
<li>建议先不要勾选&quot;使用 Readme 文件初始化这个仓库&quot;，保持仓库为空，避免后续推送时产生冲突。</li>
<li>如果账号要求 2FA（两步验证），可以先选&quot;私有&quot;创建，创建成功后去仓库设置里改成&quot;公开&quot;。</li>
<li>点击&quot;创建&quot;，保存好仓库地址（类似 <code>https://gitee.com/你的用户名/仓库名.git</code>），后面要用。</li>
</ol>
<blockquote>
<p>💡 <strong>为什么起英文名？</strong> Gitee 的仓库名只支持字母、数字、下划线和连字符，不支持中文和空格。</p>
</blockquote>
<hr />
<h4>第 2 步：初始化本地 Git 仓库</h4>
<p>在你的项目文件夹里，<strong>右键空白处</strong>，选择 <strong><code>Git Bash Here</code></strong>（或使用 Windows PowerShell 终端）。</p>
<p>依次执行以下命令：</p>
<pre><code class="language-bash"># 1. 初始化 Git 仓库（在本地建立版本管理）
git init

# 2. 配置用户身份（这一步必须做，否则无法提交）
git config --global user.name "你的Gitee用户名"
git config --global user.email "你的邮箱@qq.com"</code></pre>
<blockquote>
<p>💡 <strong>这一步的作用：</strong> <code>git init</code> 会在当前文件夹创建一个 <code>.git</code> 隐藏文件夹，Git 的所有版本记录都存放在这里。</p>
</blockquote>
<hr />
<h4>第 3 步：添加文件并提交到本地仓库</h4>
<pre><code class="language-bash"># 1. 把所有文件添加到暂存区
git add .

# 2. 提交到本地仓库
git commit -m "首次提交"</code></pre>
<blockquote>
<p>💡 <strong>命令解释：</strong></p>
<ul>
<li><code>git add .</code> ：<code>.</code> 代表当前文件夹下的所有文件，会把所有改动都放到暂存区。</li>
<li><code>git commit -m "xxx"</code> ：<code>-m</code> 是 message（备注）的缩写，后面跟的是本次提交的说明。</li>
</ul>
</blockquote>
<p><strong>可能遇到的问题：</strong></p>
<p>如果执行 <code>git commit</code> 时报错：</p>
<pre><code>Author identity unknown
*** Please tell me who you are.</code></pre>
<p>说明你没有设置用户身份，执行第 2 步的 <code>git config</code> 命令即可解决。</p>
<hr />
<h4>第 4 步：关联远程仓库并推送</h4>
<pre><code class="language-bash"># 1. 添加远程仓库地址
git remote add origin https://gitee.com/你的用户名/你的仓库名.git

# 2. 推送到远程仓库
git push -u origin master</code></pre>
<blockquote>
<p>💡 <strong>为什么叫 origin？</strong> <code>origin</code> 是 Git 默认的远程仓库别名，&quot;源头&quot;，你也可以理解成给远程地址起了一个昵称。</p>
</blockquote>
<hr />
<h4>第 5 步：解决推送过程中可能遇到的报错</h4>
<h5><strong>报错 1</strong>：<code>remote origin already exists</code></h5>
<p><strong>原因：</strong> 之前已经关联过远程仓库（比如项目是从 GitHub 克隆下来的，默认指向 GitHub）。</p>
<p><strong>解决方法：</strong> 先查看当前关联的地址：</p>
<pre><code class="language-bash">git remote -v</code></pre>
<p>如果地址不对，修改为新的 Gitee 地址：</p>
<pre><code class="language-bash">git remote set-url origin https://gitee.com/你的用户名/你的仓库名.git</code></pre>
<h5><strong> 报错 2</strong>：<code>error: src refspec master does not match any</code></h5>
<p><strong>原因：</strong> 本地分支名不是 <code>master</code>，主流平台的默认分支名是 <code>main</code>。</p>
<p><strong>解决方法：</strong> 把 <code>master</code> 改成 <code>main</code>：</p>
<pre><code class="language-bash">git push -u origin main</code></pre>
<h5><strong>报错 3</strong>：<code>failed to push some refs</code></h5>
<p><strong>原因：</strong> 远程仓库有文件（比如创建时勾选了 Readme 初始化），和本地冲突。</p>
<p><strong>解决方法：</strong> 先拉取远程内容再推送：</p>
<pre><code class="language-bash">git pull --rebase origin main
git push -u origin main</code></pre>
<hr />
<h3>四、常用命令速查表</h3>
<table>
<thead>
<tr>
<th>命令</th>
<th>作用</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>git init</code></td>
<td>在当前文件夹初始化 Git 仓库</td>
</tr>
<tr>
<td><code>git add .</code></td>
<td>把所有修改过的文件添加到暂存区</td>
</tr>
<tr>
<td><code>git commit -m "备注"</code></td>
<td>提交到本地仓库并添加备注</td>
</tr>
<tr>
<td><code>git remote -v</code></td>
<td>查看当前关联的远程仓库地址</td>
</tr>
<tr>
<td><code>git remote add origin 地址</code></td>
<td>关联远程仓库</td>
</tr>
<tr>
<td><code>git remote set-url origin 新地址</code></td>
<td>修改远程仓库地址</td>
</tr>
<tr>
<td><code>git push -u origin main</code></td>
<td>推送并关联远程分支（首次推送）</td>
</tr>
<tr>
<td><code>git push</code></td>
<td>后续推送（省略分支名）</td>
</tr>
<tr>
<td><code>git pull</code></td>
<td>拉取远程仓库的最新代码</td>
</tr>
</tbody>
</table>
<hr />
<h3>五、总结</h3>
<p>回顾整个流程，其实就三步核心操作：</p>
<pre><code class="language-bash">git add .
git commit -m "说明"
git push</code></pre>
<p>理解这三条命令的含义，你就能应对绝大多数日常代码托管需求。遇到报错不要慌，看清错误提示，再结合 <code>git remote -v</code> 等命令检查当前状态，基本都能解决。</p>
<p>希望这篇文章能帮到你。如有其他问题，欢迎在评论区交流讨论！</p>]]></description>
    <pubDate>Wed, 02 Sep 2026 13:24:19 +0800</pubDate>
    <dc:creator>雅洁</dc:creator>
    <guid>https://zhangyajie.net/?post=5</guid>
</item>
<item>
    <title>低带宽下的 S3 存储迁移：分片并发的实践与权衡</title>
    <link>https://zhangyajie.net/?post=4</link>
    <description><![CDATA[<blockquote>
<p>一次 5GB 数据的跨服务器迁移，在源端带宽仅 5Mbps 的限制下，通过分片并发将传输效率推到带宽上限。</p>
</blockquote>
<h2>一、背景与约束</h2>
<p>我维护了一个自托管的 RustFS 服务（兼容 S3 API / MinIO），主要用于存储学习教育相关的音频文件（单词/例句 MP3，约 5GB），支撑着一个小型在线教育应用。<br />
由于旧服务器即将下线，需要将全部数据迁移到新服务器。但面临两个硬约束：</p>
<table>
<thead>
<tr>
<th>约束</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>源端带宽</strong></td>
<td>旧服务器出带宽仅 5Mbps（某厂商轻量应用服务器入门型）</td>
</tr>
<tr>
<td><strong>目标端状态</strong></td>
<td>新服务器为全新实例，未安装任何存储服务软件</td>
</tr>
</tbody>
</table>
<p>如果使用最直接的 <code>scp</code> 单连接传输，理论极限速度约 625KB/s，3.5GB 压缩包需要 <strong>1.5~2 小时</strong>。在真实的公网环境下，TCP 拥塞控制、丢包重传等因素会进一步拖慢速度，且一旦 SSH 断开，传输即中断，需要从头再来。</p>
<p>这意味着：<strong>需要一种能跑满 5Mbps 带宽、且具备中断可恢复能力的传输方案。</strong></p>
<h2>二、方案选型</h2>
<h3>2.1 备选方案</h3>
<table>
<thead>
<tr>
<th>方案</th>
<th>原理</th>
<th>可行性</th>
<th>不选的原因</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>scp</code> 直传</td>
<td>单连接 SSH 传输</td>
<td>❌</td>
<td>无法充分利用带宽，无断点续传</td>
</tr>
<tr>
<td><code>rsync</code></td>
<td>增量同步 + SSH 通道</td>
<td>❌</td>
<td>小文件场景下校验开销大；目标端无服务，无法使用 daemon 模式，ssh 模式下单连接瓶颈依旧存在</td>
</tr>
<tr>
<td><code>rclone</code> 多线程</td>
<td>多连接并发，支持断点续传</td>
<td>⚠️</td>
<td>需要目标端先有一个运行中的 S3 服务，形成&quot;鸡生蛋&quot;问题</td>
</tr>
<tr>
<td><code>mscp</code> / <code>para</code></td>
<td>封装好的多线程 SCP 工具</td>
<td>❌</td>
<td>实测官方下载链接已失效（404），无法快速部署</td>
</tr>
<tr>
<td><strong>split + 并发 scp</strong></td>
<td>手动分片，多连接并行传输</td>
<td>✅</td>
<td>无额外依赖，仅需 SSH；可控性强，可观测性好</td>
</tr>
</tbody>
</table>
<h3>2.2 选择理由</h3>
<p><code>split + 并发 scp</code> 的核心思路是：<strong>将大文件切分为多个分片，每个分片通过独立的 SSH 连接并行传输</strong>。</p>
<p>这样做有两个收益：</p>
<ol>
<li><strong>多连接并发</strong>：通过建立多个 TCP 连接，减小单连接受 BDP（带宽延迟积）限制的影响，将带宽利用率从约 60% 提升到 95% 以上；</li>
<li><strong>可观测性</strong>：每个分片独立传输，可以清晰看到各分片的进度，方便排查慢连接。</li>
</ol>
<h2>三、关键设计决策</h2>
<h3>3.1 为什么先打包再分片？</h3>
<p>原始数据是 5GB 的目录树，包含数千个 MP3 小文件。如果直接分片目录，会产生两个问题：</p>
<ul>
<li>每个小文件都需要建立 SSH 连接，握手开销远大于传输本身；</li>
<li>文件分配不均衡，无法控制每个分片的大小。</li>
</ul>
<p>因此选择 <strong>先 tar 打包成单文件，再 split 切分</strong>，将小文件的元数据开销摊销到一次打包中。</p>
<h3>3.2 分片大小为什么选 500MB？</h3>
<p>这是一个需要权衡的参数：</p>
<table>
<thead>
<tr>
<th>分片大小</th>
<th>并发度</th>
<th>优势</th>
<th>劣势</th>
</tr>
</thead>
<tbody>
<tr>
<td>太小（如 100MB）</td>
<td>35 个分片</td>
<td>并发度高</td>
<td>SCP 握手次数多；后台管理 35 个进程，资源开销大</td>
</tr>
<tr>
<td>适中（500MB）</td>
<td>7 个分片</td>
<td>并发度足够填满 5Mbps；进程数可控</td>
<td>单个分片传输失败重传代价尚可接受</td>
</tr>
<tr>
<td>太大（1GB）</td>
<td>4 个分片</td>
<td>管理简单</td>
<td>并发度不足，无法充分利用带宽</td>
</tr>
</tbody>
</table>
<p><strong>500MB 是在并发度和管理成本之间的一个平衡点。</strong> 7 个并发连接足以将 5Mbps 带宽跑满，同时进程数在 <code>ps</code> 和 <code>jobs</code> 的视野内清晰可查。</p>
<h3>3.3 为什么用 SCP 而不是 HTTPS？</h3>
<ul>
<li>新服务器预装了 SSH 服务，无需额外部署；</li>
<li>通过 <code>ssh-copy-id</code> 配置免密登录后，所有 <code>scp</code> 命令自动复用同一个密钥，无需处理 Token 过期或签名计算。</li>
</ul>
<h2>四、实现与踩坑</h2>
<h3>4.1 打包</h3>
<pre><code class="language-bash">tar -czf /tmp/rustfs_data_backup.tar.gz -C /www/wwwroot/rustfs data</code></pre>
<p>打包后大小：3.5GB（MP3 本身已压缩，gzip 压缩率有限）。</p>
<h3>4.2 切分与并发传输</h3>
<pre><code class="language-bash"># 切分为每个 500MB 的分片
split -b 500M -d --suffix-length=2 rustfs_data_backup.tar.gz rustfs_part_</code></pre>
<p>split 命令各参数含义：</p>
<ul>
<li>-b 500M：每个分片大小为 500MB；</li>
<li>-d：使用数字后缀（00、01…），而非字母后缀；</li>
<li>--suffix-length=2：后缀长度为 2 位，支持最多 99 个分片；</li>
<li>rustfs<em>part</em>：分片文件的前缀。</li>
</ul>
<p>执行后生成分片文件</p>
<pre><code class="language-bash"># 配置免密登录（避免多次密码输入）
ssh-keygen -t rsa -b 4096 -N "" -f ~/.ssh/id_rsa
ssh-copy-id root@目标服务器ip</code></pre>
<p>验证免密登录是否生效：</p>
<pre><code class="language-bash">ssh root@目标服务器ip "echo 'OK'"</code></pre>
<pre><code class="language-bash"># 并发传输
for part in rustfs_part_*; do
    scp "$part" root@目标服务器ip:/tmp/ &amp;
done
wait</code></pre>
<p>这段脚本的执行逻辑：</p>
<ul>
<li>for part in rustfs<em>part</em>*：遍历所有分片文件；</li>
<li>scp ... &amp;：每个分片通过 &amp; 放入后台执行，不阻塞下一个分片的启动；</li>
<li>wait：等待所有后台 scp 进程完成，再继续后续操作。</li>
</ul>
<p>实际传输效果：多个分片同时传输，单分片速度约 80~90KB/s，总带宽稳定在 620KB/s 左右，接近 5Mbps 的理论上限。</p>
<h3>4.3 目标端合并</h3>
<pre><code class="language-bash"># 合并分片
cat rustfs_part_* &gt; rustfs_data_backup.tar.gz

# 验证合并结果
ls -lh rustfs_data_backup.tar.gz
tar -tzf rustfs_data_backup.tar.gz | head -20</code></pre>
<p>踩坑记录：在执行合并操作时遇到 No space left on device 报错。检查磁盘后发现根分区 / 已满，而 /www 数据分区还有充足空间。解决方案是将分片移动到 /www/temp 目录后再合并，避免写入系统分区。</p>
<h3>4.4 解压与启动</h3>
<pre><code class="language-bash"># 创建数据目录
mkdir -p /www/wwwroot/rustfs

# 解压数据
tar -xzvf rustfs_data_backup.tar.gz -C /www/wwwroot/rustfs

# 启动 RustFS 容器
docker run -d \
  --name rustfs \
  --restart always \
  -p 9000:9000 \
  -p 9001:9001 \
  -e RUSTFS_ROOT_USER='&lt;用户名&gt;' \
  -e RUSTFS_ROOT_PASSWORD='&lt;你的密码&gt;' \
  -e MINIO_SERVER_URL='http://&lt;你的存储域名&gt;' \
  -e MINIO_BROWSER_REDIRECT_URL='http://&lt;你的控制台域名&gt;' \
  -v /&lt;你的宿主机路径&gt;/data:/data \
  -v /&lt;你的宿主机路径&gt;/config:/config \
  rustfs/rustfs</code></pre>
<p>验证容器运行状态：</p>
<pre><code class="language-bash">docker ps | grep rustfs
docker logs rustfs --tail 20</code></pre>
<h2>五、延伸思考：方案的局限性</h2>
<p>这套方案适用于：</p>
<ul>
<li>数据量在 10GB 以内</li>
<li>源端带宽在 50Mbps 以下</li>
<li>目标端无需预先部署任何服务</li>
</ul>
<p>但如果数据量增长到 500GB，这套方案将不再适用。更合适的选择包括：</p>
<ul>
<li>使用 rclone 的多线程上传到对象存储中转（如 AWS S3 / 腾讯云 COS）；</li>
<li>使用专业工具如 bbcp（专为高速网络设计）或 fpart（并行文件传输）；</li>
<li>若两台服务器同属一个云厂商，可使用内网高速通道 + 快照迁移。</li>
</ul>
<h2>六、命令速查</h2>
<pre><code class="language-bash"># 打包
tar -czf backup.tar.gz -C /source data

# 验证压缩包
tar -tzf backup.tar.gz | head -20

# 分片
split -b 500M -d --suffix-length=2 backup.tar.gz part_

# 免密登录
ssh-keygen -t rsa -b 4096
ssh-copy-id root@target_ip

# 并发传输
for f in part_*; do scp "$f" root@target:/path/ &amp; done; wait

# 合并
cat part_* &gt; backup.tar.gz

# 查看磁盘空间
df -h</code></pre>
<p>📌 本文所有操作在 CentOS 7/8 环境下验证通过，RustFS 版本为 v1.0+。</p>
<pre><code></code></pre>]]></description>
    <pubDate>Wed, 26 Aug 2026 13:52:06 +0800</pubDate>
    <dc:creator>雅洁</dc:creator>
    <guid>https://zhangyajie.net/?post=4</guid>
</item>
<item>
    <title>别再手动敲了！1分钟教你扒下网页里的表格数据</title>
    <link>https://zhangyajie.net/?post=3</link>
    <description><![CDATA[<p>你是不是经常遇到这种情况：在网上看到一张超有用的数据表，想存下来自己用，但网站偏偏不给下载按钮？</p>
<p>复制粘贴？格式全乱套。一个个敲？那是程序员最痛恨的体力活。</p>
<p>今天带来一个小技巧，利用浏览器自带的&quot;隐身&quot;功能，3步把网页表格&quot;连根拔起&quot;。</p>
<hr />
<h2>核心技术：<code>copy()</code> 大法</h2>
<h2>操作步骤（全程无需安装任何软件）</h2>
<h3>1. 选中表格</h3>
<p>在网页上，鼠标右键点击那个表格，选择 <strong>&quot;检查&quot;</strong>（或者按 <code>F12</code>，点左上角的小箭头选中表格）。</p>
<h3>2. 定位代码</h3>
<p>在开发者工具（Elements 面板）中，确保高亮的那行代码是 <code>&lt;table ...&gt;</code> 开头的那一串。</p>
<h3>3. 输入魔法咒语</h3>
<p>切换到 <strong>Console（控制台）</strong> 标签，粘贴下面这行代码，然后敲回车：</p>
<pre><code class="language-javascript">copy(document.querySelector('table').outerHTML);</code></pre>
<h3>4. 粘贴到 Excel</h3>
<p>打开你的 Excel，直接按 <code>Ctrl + V</code> 粘贴。</p>
<h3>5. 见证奇迹</h3>
<p>你会看到，表格的结构（行、列、颜色）被完美保留下来了！</p>
<hr />
<h2>进阶小贴士</h2>
<p>如果页面里有多个表格，上面的代码只会抓<strong>第一个</strong>。</p>
<p>想抓第二个？把括号里的 <code>'table'</code> 换成下面这样就行（数字从 <code>0</code> 开始数）：</p>
<pre><code class="language-javascript">document.querySelectorAll('table')[1]</code></pre>
<p>完整代码：</p>
<pre><code class="language-javascript">copy(document.querySelectorAll('table')[1].outerHTML);</code></pre>
<hr />
<h2>小提示</h2>
<p>这个方法只对<strong>正经的 HTML 表格</strong>有效。如果遇到那种 PDF 转图片的&quot;假表格&quot;，这个方法就失灵了——那你就只能老老实实截图，或者用 OCR 文字识别了。</p>
<hr />
<p><strong>你平时遇到这种数据，都是怎么处理的？欢迎在评论区聊聊 👇</strong></p>]]></description>
    <pubDate>Fri, 14 Aug 2026 13:48:13 +0800</pubDate>
    <dc:creator>雅洁</dc:creator>
    <guid>https://zhangyajie.net/?post=3</guid>
</item>
<item>
    <title>技术小白也能独立建站？我的真实部署笔记</title>
    <link>https://zhangyajie.net/?post=2</link>
    <description><![CDATA[<h1>从零搭建个人博客：一次完整的服务器部署与 EMLOG 应用实践</h1>
<p>一直以来想拥有一个完全属于自己的内容发布平台。对比了市面上主流方案后，我决定从云服务器层面开始，独立完成整个博客站点的部署，以此作为个人技术实践的一个小小起点。</p>
<p>这篇文章记录了从选型到上线的主要过程，也是一次完整的技术复盘。</p>
<hr />
<h2>成本明细</h2>
<table>
<thead>
<tr>
<th>项目</th>
<th>规格</th>
<th>成本</th>
</tr>
</thead>
<tbody>
<tr>
<td>域名</td>
<td>zhangyajie.net</td>
<td>约 100元/年</td>
</tr>
<tr>
<td>云服务器</td>
<td>腾讯云轻量应用服务器（4核4G，3M带宽）</td>
<td>约 100元/年</td>
</tr>
</tbody>
</table>
<p>选择轻量服务器的原因是性价比高、配置灵活，满足个人站点的性能需求。</p>
<hr />
<h2>技术选型</h2>
<table>
<thead>
<tr>
<th>模块</th>
<th>选型</th>
<th>选择理由</th>
</tr>
</thead>
<tbody>
<tr>
<td>操作系统</td>
<td>CentOS</td>
<td>主流 Linux 发行版，社区成熟</td>
</tr>
<tr>
<td>管理面板</td>
<td>宝塔面板</td>
<td>提升运维效率，可视化操作</td>
</tr>
<tr>
<td>运行环境</td>
<td>LNMP（Nginx + MySQL + PHP）</td>
<td>稳定高效的 Web 服务组合</td>
</tr>
<tr>
<td>博客程序</td>
<td>EMLog Pro</td>
<td>轻量级、易扩展，资源占用低</td>
</tr>
</tbody>
</table>
<hr />
<h2>实践过程</h2>
<h3>第一阶段：环境准备</h3>
<ul>
<li>完成域名注册与 ICP 备案（备案周期约 30 天）</li>
<li>完成云服务器购买与系统初始化</li>
<li>通过 SSH 连接服务器，完成宝塔面板的安装</li>
<li>通过宝塔面板一键部署 LNMP 环境</li>
</ul>
<h3>第二阶段：站点创建与程序部署</h3>
<ul>
<li>在宝塔面板左侧菜单点击&quot;网站&quot;，选择&quot;添加站点&quot;，填入已绑定的域名，其余选项保持默认，点击提交完成站点创建</li>
<li>从 EMLOG 官网下载 Pro 版本安装包（版本 2.6.23），得到一个 <code>.zip</code> 压缩文件</li>
<li>在宝塔面板的&quot;文件&quot;管理中找到站点根目录（路径为 <code>/www/wwwroot/域名/</code>），将压缩包直接拖拽上传至该目录，右键选择&quot;解压&quot;，解压后将所有文件从子目录剪切至根目录</li>
<li>在宝塔面板的&quot;文件&quot;管理中，右键站点根目录，选择&quot;权限&quot;，将权限设置为 <code>755</code>，确保程序在安装过程中拥有足够的写入权限</li>
</ul>
<h3>第三阶段：应用安装与上线</h3>
<ul>
<li>浏览器访问域名，系统自动跳转至 EMLOG 安装向导页面</li>
<li>在宝塔面板左侧菜单点击&quot;数据库&quot;→&quot;添加数据库&quot;，填写数据库名称、用户名、密码并提交，完成数据库创建</li>
<li>将数据库信息（数据库名、用户名、密码、数据库地址）逐一填入安装向导对应输入框，点击&quot;下一步&quot;</li>
<li>设置站点名称、管理员账号及登录密码，点击&quot;完成安装&quot;</li>
<li>在宝塔面板的站点设置中，点击&quot;SSL&quot;→&quot;Let's Encrypt&quot;→&quot;申请&quot;，等待约1分钟证书自动签发，勾选&quot;强制HTTPS&quot;并保存，站点地址栏显示小锁图标</li>
</ul>
<hr />
<h2>遇到的技术问题与解决</h2>
<p><strong>问题：</strong> 域名解析完成后，站点无法立即访问。</p>
<p><strong>排查过程：</strong> 检查了服务器安全组放行端口、宝塔面板站点配置，均无异常。最终确认是 DNS 解析生效存在延迟（通常需要数分钟至数小时）。</p>
<p><strong>解决方案：</strong> 等待解析生效后，站点恢复正常访问。</p>
<p>这个过程让我对 DNS 解析机制有了更直观的认识。</p>
<hr />
<h2>后续方向</h2>
<p>站点已稳定运行，后续计划：</p>
<ul>
<li>根据实际需求对主题进行二次调整</li>
<li>持续输出技术笔记与项目复盘</li>
<li>探索服务器层面的运维优化</li>
</ul>
<hr />
<h2>小结</h2>
<p>整个实践过程涵盖了域名注册、环境部署、应用发布等核心环节，让我对 Web 服务的完整链路有了第一手的认知。这次经历也是一次有价值的能力拓展。</p>]]></description>
    <pubDate>Tue, 04 Aug 2026 10:43:42 +0800</pubDate>
    <dc:creator>雅洁</dc:creator>
    <guid>https://zhangyajie.net/?post=2</guid>
</item>
</channel>
</rss>