牙叔教程 简单易懂
大漠教师在写了一个课程: 现代 Web 布局
好评如潮

可是来喽,
课程里边有一些微不足道的过错, 趁着ChatGPT的热度,
我来道一道, 大漠教师文章里的小过错,
底部有本文的代码库房链接
流程图草稿

因为ChatGPT直接手文字, 所以我把这个流程图用文字描述一下
ChatGPT生成项目目录
prompt提示语
我要创立一个项目目录,
项目的功用是找出课程中的过错,
课程是用多篇文章写的, 该课程在平台上架了,
项目言语:Node.js,
我要用Nodejs爬取平台上的这个课程"现代 Web 布局",
并找出课程里一切文章的过错,
而且保存到本地,
数据保存为json格局,
建议一个独自的文件夹放找出的过错,
每篇文章的过错放到一个独自json文件中,
json文件内容是一个数组, 里边是目标,目标有以下特点:
- 找出的过错
- 过错来自于那段话
- 过错的原因
- 怎么改正过错
找过错的过程
1. 经过Nodejs爬虫, 提取课程里一切的文章链接
2. 经过文章链接爬取文章的正文
3. 把正文发给ChatGPT, 让他找出过错
4. 把找到的过错保存到本地的指定收集过错的文件夹中
请给我一个项目目录
备注: 我不需求单元测试目录
ChatGPT生成的目录
好的,以下是一个或许的项目目录结构:
```
web-layout-error-finder/
├── node_modules/ // 寄存 Node.js 依靠包
├── errors/ // 寄存找到的过错
│ ├── article1.json // 榜首篇文章的过错信息
│ ├── article2.json // 第二篇文章的过错信息
│ ├── ...
├── src/ // 寄存源代码
│ ├── crawler.js // 爬虫模块
│ ├── errorFinder.js // 过错查找模块
│ ├── main.js // 程序进口
│ └── utils.js // 东西函数
├── package.json // 项目装备文件
└── README.md // 项目文档
```
接下来,咱们能够进一步解释每个目录和文件的作用:
- `node_modules/`:寄存 Node.js 应用程序所需的一切依靠项。经过运转 `npm install` 指令将它们装置到该目录。
- `errors/`:寄存找到的过错。每篇文章对应一个 JSON 文件,里边是一个数组,数组中的每个元素都是一个目标,描述一条过错及其相关信息。
- `src/`:寄存源代码。
- `crawler.js`:这个模块担任爬取网站上的文章链接和文章内容。
- `errorFinder.js`:这个模块担任调用 ChatGPT API,找出文章中的过错,并将找到的过错保存到本地。
- `main.js`:这个模块是程序的进口,担任和谐其他模块的工作。
- `utils.js`:这个模块包括一些小的东西函数,用于处理一些常见的操作。
- `package.json`:此文件是 Node.js 项目的装备文件。它包括项目名称、版本号、依靠项等信息。
- `README.md`:项目文档,包括阐明、运用办法、留意事项等。
希望这个目录结构对您有所协助!
爬课程目录
由所以付费课程, 所以肯定要Cookie, 因而我的prompt是这样的
我要爬取这个网页的正文
https:///book/7161370789680250917?scrollMenuIndex=1
运用Nodejs, 爬取的时分需求添加cookie, 请给我爬取正文的代码
ChatGPT答复
好的,以下是运用 Node.js 爬取图书正文的示例代码:
javascript
const axios = require('axios');
const cheerio = require('cheerio');
// 设置恳求头和 cookie
const headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Cookie': '填写你的 Cookie'
};
// 要爬取的页面 URL
const url = 'https:///book/7161370789680250917?scrollMenuIndex=1';
// 发送 GET 恳求
axios.get(url, { headers })
.then(response => {
// 运用 cheerio 加载 HTML 文档
const $ = cheerio.load(response.data);
// 获取正文内容
const content = $('.main-section .section').html();
// 输出成果
console.log(content);
})
.catch(error => {
console.error(error);
});
上面的代码运用了 axios 库发送 HTTP 恳求,并设置了恳求头和 Cookie。然后,运用 cheerio 库加载 HTML 文档,并经过 jQuery 风格的挑选器获取到了正文内容。
留意:上面的示例代码中,需求自行替换 Cookie 的值为自己的实践 Cookie 值。
希望这个示例对您有所协助!
这儿涉及到一点爬虫的常识, 找目录链接之类的常识, 打开开发者, 一个一看看就找出来了,
我不会供给url, 爬虫有风险, 你们懂的
这是我修改后的代码
const axios = require("axios");
const config = require("./config");
async function getDir() {
const url = config.url.目录;
const headers = config.headers.目录;
let res = await axios.post(
url,
{
booklet_id: "7161370789680250917",
},
{
headers: headers,
}
);
const sections = res.data.data.sections;
console.log(sections[0]);
return res;
}
getDir();
至此咱们获取到了目录
{
id: 88871,
section_id: '7161370789768347685',
title: 'Web 布局技能演进:了解 Web 布局发展史 ',
user_id: '1908407916041614',
booklet_id: '7161370789680250917',
status: 1,
content: '',
draft_content: '',
draft_title: 'Web 布局技能演进:了解 Web 布局发展史 ',
markdown_content: '',
markdown_show: '',
is_free: 1,
read_time: 1786,
read_count: 9234,
comment_count: 38,
ctime: 1667444849,
mtime: 1667444849,
is_update: 0,
draft_read_time: 0,
vid: '',
reading_progress: {
id: 0,
booklet_id: '7161370789680250917',
user_id: '2295436007442622',
section_id: '7161370789768347685',
reading_end: 0,
reading_progress: 97,
reading_position: 0,
has_update: 1,
last_rtime: 1669955278,
ctime: 1669888750,
mtime: 1669952433
}
}
和网页内容比对一下, 是正确的

爬取榜首篇文章
这是文章对应的特点

咱们要以下特点
- title 用来保存过错的文件名
- markdown_show 文章正文
代码, 和上面一模一样, 仅仅字段不一样;
瞧这代码, 根本没变
async function getFirst() {
const url = config.url.first;
const headers = config.headers.first;
let res = await axios.post(
url,
{
section_id: "7161370789768347685",
},
{
headers: headers,
}
);
const section = res.data.data.section;
console.log(section);
return res;
}
下载一切文章
假如网络产生过错, 或许其他异常, 咱们要重启程序;
还要再爬一遍数据, 所以咱们先把文章都下载下来, 这样就不必再次下载了,
一次下载, 终身运用
这儿其实不需求prompt, 可是我仍是要用它, 便是这么有鸟性
prompt 讨教ChatGPT怎么批量下载文章
我要下载一个课程中的一切章节
提取课程的目录信息的代码是这样的
```
async function getDir() {
const url = config.url.目录;
const headers = config.headers.目录;
let res = await axios.post(
url,
{
booklet_id: "7161370789680250917",
},
{
headers: headers,
}
);
const sections = res.data.data.sections;
return sections;
}
```
sections里边保存的是目录信息,
sections是一个数组, 数组中都是目标, 数组的内容如下
```
[
{
"id": 88871,
"section_id": "7161370789768347685",
"title": "Web 布局技能演进:了解 Web 布局发展史 ",
"user_id": "1908407916041614",
"booklet_id": "7161370789680250917",
"status": 1,
"content": "",
"draft_content": "",
"draft_title": "Web 布局技能演进:了解 Web 布局发展史 ",
"markdown_content": "",
"markdown_show": "",
"is_free": 1,
"read_time": 1786,
"read_count": 9234,
"comment_count": 38,
"ctime": 1667444849,
"mtime": 1667444849,
"is_update": 0,
"draft_read_time": 0,
"vid": "",
},
...
]
```
咱们要提取的目录中每个章节的以下特点
- section_id
- title
提取到一切章节的特点今后, 咱们要开端获取一切的文章数据,
获取文章数据的代码是这样的
```
async function getSection(section_id) {
const url = config.url.first;
const headers = config.headers.first;
let res = await axios.post(
url,
{
section_id: section_id
},
{
headers: headers,
}
);
const section = res.data.data.section;
return section;
}
```
获取到的section是一个目标, 内容一般是这样的
```
{
"title": "Flexbox 中的核算:经过扩展因子比例来扩展 Flex 项目",
"markdown_show": "文章的正文..."
}
```
获取到section今后, 咱们要保存数据到本地,
文件的数量由之前的, 从目录获取章节的数量决议,
每个章节的正文, 便是section的字段markdown_show的值,
咱们要保存每个章节的内容,到一个指定的文件夹, 文件夹名字是sections
文件的名字是section的字段title的值, 记住要去掉title的值的一切特别符号, 因为文件名不能含有特别符号, 比方空格, 冒号等特别字符;
现在请你编写程序, 下载课程一切的章节,
运用言语: Node.js
ChatGPT的答复
首要需求装置axios和fs模块,能够运用以下指令进行装置:
Copy
npm install axios fs
然后能够编写代码:
Copy
const axios = require('axios');
const fs = require('fs');
const sanitize = require("sanitize-filename");
const config = {
url: {
目录: 'https://www.xxx.com/api/booklet/sections',
first: 'https://www.xxx.com/api/section/first',
},
headers: {
目录: {
'Content-Type': 'application/json;charset=UTF-8',
'Cookie': 'xxx'
},
first: {
'Content-Type': 'application/json;charset=UTF-8',
'Cookie': 'xxx'
}
}
};
async function getDir() {
const url = config.url.目录;
const headers = config.headers.目录;
let res = await axios.post(
url,
{
booklet_id: "7161370789680250917",
},
{
headers: headers,
}
);
const sections = res.data.data.sections;
return sections;
}
async function getSection(section_id) {
const url = config.url.first;
const headers = config.headers.first;
let res = await axios.post(
url,
{
section_id: section_id
},
{
headers: headers,
}
);
const section = res.data.data.section;
return section;
}
async function downloadCourse() {
const sections = await getDir();
const dirPath = './sections';
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath);
}
for (let i = 0; i < sections.length; i++) {
const section = await getSection(sections[i].section_id);
const filename = sanitize(sections[i].title) + '.md';
fs.writeFileSync(dirPath + '/' + filename, section.markdown_show);
console.log('Downloaded: ' + filename);
}
}
downloadCourse();
在代码中,首要经过调用getDir函数获取课程的目录信息,然后创立一个名为sections的文件夹用于保存一切的章节文件。
接着运用一个循环遍历每个章节,经过调用getSection函数获取章节的具体内容,将获取到的内容保存到本地的文件中。
在保存文件时,需求运用sanitize-filename模块对文件名进行处理,去除一切的特别符号,确保文件名的合法性。
最终运转downloadCourse函数即可开端下载课程一切的章节。

- 我都没有给ChatGPT说我的config字段的装备是什么, 他自己就估测出来了,Oh my God
- sanitize-filename, 这又是啥? 我都没见过, 就问你服不服气? 我是服了
咱们来履行以下他给的代码, 我略加修改, 运转看作用
$ npm run main
> my-project@1.0.0 main
> node src/main.js
Downloaded: Web 布局技能演进:了解 Web 布局发展史.md
Downloaded: 现代 Web 布局技能术语.md
Downloaded: Flexbox 布局根底运用.md
Downloaded: Flexbox 布局中的对齐办法.md
Downloaded: Flexbox 布局中的 flex 特点的根底运用.md
Downloaded: Flexbox 中的核算:经过扩展因子比例来扩展 Flex 项目.md
Downloaded: Flexbox 中的核算:经过缩短因子比例缩短 Flex 项目.md
Downloaded: Flexbox 布局中的 flex-basis:谁能决议 Flex 项目的大小?.md
Downloaded: 运用 Flexbox 构建经典布局:10 种经典 Web 布局.md
Downloaded: Grid 布局的根底常识.md
Downloaded: 界说一个网格布局.md
Downloaded: Grid 布局中的核算.md
Downloaded: 可用于 Grid 布局中的函数.md
Downloaded: 网格项目的放置和层叠.md
Downloaded: Grid 布局中的对齐办法.md
Downloaded: 网格布局中的子网格和嵌套网格.md
Downloaded: 运用子网格构建 Web 布局.md
Downloaded: 运用 Grid 构建经典布局:10 种经典布局.md
Downloaded: 运用 Grid 构建创意性 Web 布局.md
Downloaded: Flexbox or Grid:怎么挑选合适的布局?.md
Downloaded: display:contents 改动 Flexbox 和 Grid 布局形式.md
Downloaded: Web 中的向左向右:Flexbox 和 Grid 布局中的 LTR 与 RTL.md
Downloaded: Web 中的向左向右:Web 布局中 LTR 切换到 RTL 常见过错.md
Downloaded: 内在 Web 规划.md
Downloaded: 创立不规矩 Web 布局.md
Downloaded: 怎么构建呼应式 UI?.md
Downloaded: 下一代呼应式 Web 规划:组件式驱动式 Web 规划.md
Downloaded: 下一代呼应式 Web 规划:容器查询.md


没有一点点过错, 履行今后, 彻底达到了我想要的作用,
数据现已搞下来了, 接下来就开端找大漠教师的文章中的过错了
找大漠教师的过错
构造prompt, 让ChatGPT找文章的过错
在本地有一个文件夹sections, 里边是markdown文件, 你要遍历sections中的一切markdown文件, 找出文章中的过错;
找每篇文章的过错的过程:
1. 从sections中读取markdown文件内容, 比方: Grid 布局中的核算.md
2. 经过https://api.openai.com/v1/chat/completions 接口, 传入markdown文件内容, 得到回来成果
3. 把回来的成果中的文本字段保存到文件夹errors中, 文件名便是你读取的那个文件的名字, 比方: Grid 布局中的核算.md
以上是找过错的大概过程, 下面有一些留意事项
1. 因为completions 接口有次数约束, 每次的问题和答案都不能超越1024个字符, 所以你要把markdown文件内容分段, 每段最多1024个字符, 一共分红几段, 然后每段都调用一次completions 接口, 把回来的成果都保存到errors文件夹中
2. 你给completions 接口提交数据的时分, 要指示ChatGPT回来的格局, 格局要求如下:
1. 回来的有必要是markdown格局的内容
2. 有必要包括4个标题, 别离是: 过错地点的文件名, 过错的地点的阶段, 过错的理由, 改正过错的办法
以上是我想到的, 你能够自己再想想, 有什么要弥补的你能够弥补, 在符合我的要求的情况下, 你能够自己决议怎么做
现在, 请你用Nodejs写代码, 完成以上要求.
ChatGPT的答复
首要需求装置axios和fs模块,能够运用以下指令进行装置:
Copy
npm install axios fs
然后能够编写代码:
Copy
const axios = require('axios');
const fs = require('fs');
const sanitize = require('sanitize-filename');
const config = {
url: 'https://api.openai.com/v1/chat/completions',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY',
},
};
async function findErrors() {
const dirPath = './sections';
const errorsPath = './errors';
if (!fs.existsSync(errorsPath)) {
fs.mkdirSync(errorsPath);
}
const files = fs.readdirSync(dirPath);
for (let i = 0; i < files.length; i++) {
const filePath = dirPath + '/' + files[i];
if (fs.statSync(filePath).isFile()) {
const content = fs.readFileSync(filePath, 'utf-8');
const chunks = splitContent(content);
let errors = '';
for (let j = 0; j < chunks.length; j++) {
const result = await getCompletions(chunks[j]);
if (result.choices.length > 0) {
const text = result.choices[0].text;
const errorText = generateErrorText(files[i], chunks[j], text);
errors += errorText + '\n\n';
}
}
if (errors !== '') {
const filename = sanitize(files[i]);
fs.writeFileSync(errorsPath + '/' + filename, errors);
console.log('Found errors in: ' + filename);
}
}
}
}
function splitContent(content) {
const chunks = [];
const lines = content.split('\n');
let chunk = '';
for (let i = 0; i < lines.length; i++) {
if (chunk.length + lines[i].length + 1 <= 1024) {
chunk += lines[i] + '\n';
} else {
chunks.push(chunk);
chunk = lines[i] + '\n';
}
}
if (chunk !== '') {
chunks.push(chunk);
}
return chunks;
}
async function getCompletions(prompt) {
const data = {
prompt: prompt,
max_tokens: 1024,
temperature: 0.7,
n: 1,
stop: '\n',
format: 'markdown',
};
const res = await axios.post(config.url, data, { headers: config.headers });
return res.data;
}
function generateErrorText(filename, chunk, text) {
const errorText = '## 文件名\n\n' + filename + '\n\n' +
'## 阶段\n\n' + chunk + '\n\n' +
'## 过错原因\n\n' + text + '\n\n' +
'## 改正办法\n\n';
return errorText;
}
findErrors();
在代码中,首要经过调用fs.readdirSync函数获取sections文件夹中的一切文件,然后循环遍历每个文件,读取其内容并将内容分红多个阶段。
接着,调用getCompletions函数将每个阶段提交给ChatGPT,获取回来成果中的文本,并运用generateErrorText函数将文件名、阶段、过错原因和改正办法组合成过错文本。
将一切的过错文本组合成一个字符串,假如该字符串不为空,则将其保存到errors文件夹中,文件名与原文件名相同。
在调用getCompletions函数时,需求指定ChatGPT回来的格局为markdown格局,而且包括4个标题,别离是过错地点的文件名、过错的地点的阶段、过错的理由和改正过错的办法。
留意,因为ChatGPT有次数约束,每次提交的数据不能超越1024个字符,因而需求将文章内容分红多个阶段,并别离提交给ChatGPT。
最终运转findErrors函数即可开端查找一切文章中的过错,并将过错信息保存到本地的文件中。
这个代码也要略加修改才能用, 尤其要留意的一点是
max_tokens: 1024
这个约束的是chatgpt呼应的tokens, 不包括你的prompt, 也便是你给chatgpt提出的问题;
可是,
总的字数是4096 tokens, 因而你这儿假如过写3000, 那么你的问题就最多写1096,
再次可是,
prompt, 也便是问题, 你是能够操控的, chatgpt回来的值你操控不了,
因而, 为了尽或许的给chatgpt的答复, 供给满足的tokens, 咱们的发问的字数应该尽量少一些;
代码里的过错
async function getCompletions(prompt) {
const data = {
prompt: prompt,
max_tokens: 1024,
temperature: 0.7,
n: 1,
stop: '\n',
format: 'markdown',
};
const res = await axios.post(config.url, data, { headers: config.headers });
return res.data;
}
他这个api现已更新了, 可是chatgpt的库中的数据还没更新, 仍是老接口, 这个接口要自己改一下
const data = {
model: "gpt-3.5-turbo",
messages: [{ role: "user", content: role + prompt + suffix }],
temperature: 0.7,
max_tokens: 3000,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0,
stream: false,
};
const res = await axios.post("https://api.openai.com/v1/chat/completions", data, {
headers: config.headers.chatgpt,
httpsAgent: agent,
});
return res.data.choices[0].message.content;
因为ChatGPT有字数约束, 因而咱们把文章拆开了, 一小段一小段的纠错,
prompt用于文章纠错
const role = `
现在给你看一篇文章, 假如文章里边有过错, 请你把它指出来,
你要依照以下要求回复内容:
1. 生成的回复内容长度禁止超越1500个字, 假如超出了, 后边的内容丢掉, 此条规矩, 优先级最高;
2. 回来的有必要是markdown格局的内容
3. 有必要包括这些标题, 别离是: 过错地点的阶段, 过错的理由, 改正过错的办法
4. 其间, 标题为"过过错地点的阶段", 写阶段中的10个字即可
分割线后边是你要剖析的文章内容, 请你剖析文章, 而且把过错指出来, 而且依照我的要求回复.
-----------------------------------------------------------------------
`;
ChatGPT的答复
# 过错地点的阶段
第二段
# 过错的理由
过错地描述了CSS的writing-mode、direction和HTML的dir对Flexbox布局中对齐特点的影响。
# 改正过错的办法
CSS的writing-mode、direction和HTML的dir对Flexbox布局中对齐特点并没有影响,它们仅仅影响Web排版的方向。因而,应该将描述修改为:在Flexbox布局中,对齐特点都会受到flex-direction特点的影响,其间justify-特点一直用于在主轴上对齐,align-特点一直用于在侧轴上对齐。
无限等待
接下来就交给chatgpt, 批量查找文章的过错了,
api缓慢运转中, 大概过了好久, 好久, long, long, ago

刺客深深的领会到了, 什么叫做慢, 都运转几个小时了, 还没跑完, 早知道, 我就去找个速度快的接口, 向chargpt发问了, 现在这个特别慢,
…
又过了好久, 总算跑完了

展示几个微小的过错
他说大漠教师的CSS写的不标准, 我不要你觉得, 我要我觉得,
我觉得大漠教师写的CSS老棒了, 是我的100倍
## 过错地点的阶段
榜首段
## 过错的理由
文中的CSS代码存在一些语法过错和不标准的写法。
## 改正过错的办法
1. 文中的 `container-type: inline-size;` 应该改为 `contain: inline-size;`,正确的写法是 `contain`。
2. 文中在 `.card` 款式中设置 `border-radius: 0;`,然后在 `@container` 中再设置 `border-radius: 8px;`,这样不够简洁。能够将 `.card` 款式的 `border-radius` 放到 `:root` 中界说一个变量,然后在 `@container` 中运用 `clamp()` 函数改动变量的值,再运用变量设置 `border-radius`,这样愈加简洁标准。
更正后的代码如下:
```
:root {
--w: 760px;
--max-radius: 8px;
--min-radius: 0px; /* 这儿的单位不能省略 */
--radius: calc(100vw - var(--w));
--responsive-radius: clamp(var(--min-radius), var(--radius), var(--max-radius));
--card-radius: 0; /* 界说卡片的圆角 */
}
.card {
border-radius: var(--card-radius); /* 运用界说好的变量 */
}
@container (width > 700px) {
:root {
--card-radius: var(--max-radius); /* 运用clamp()函数改动变量的值 */
}
}
```
修改后的代码愈加标准,也愈加明晰易懂。
这个说大漠教师指令不标准
### 过错地点的阶段
第二段
### 过错的理由
该段代码中的命名办法不标准,简单混淆和出错。
### 改正过错的办法
统一运用小写字母和连字符来命名,一起遵从语义化命名规矩,使命名愈加明晰易懂。
修改后的代码如下:
```CSS
.title {
grid-area: title;
}
.aside {
grid-area: aside;
}
.main {
grid-area: main;
}
.banner {
grid-area: banner;
}
.fig-1 {
grid-area: fig-1;
}
.fig-2 {
grid-area: fig-2;
}
```
一起,在CSS中运用BEM命名标准或其他命名标准能够进一步提高代码的可读性和可维护性。
大漠教师用词不准
## 过错地点的阶段
榜首段
## 过错的理由
该阶段中的用语不精确,存在歧义和语病。
## 改正过错的办法
1. 将“受众”改为“用户”愈加精确和通俗易懂;
2. “受众”与“一个人”并不是彻底对立的关系,能够改为“咱们将愈加注重用户个性化需求,供给更好的内容和体验。”;
3. “Web 真正的可移植”不太精确,能够改为“使得网站在各种设备上均可正常显示和运用”。
修改后的文章如下:
咱们不再是为用户集体规划。咱们对 "用户"一词的了解将产生变化,因为咱们将愈加注重用户个性化需求,供给更好的内容和体验。 组件驱动的呼应式 Web 规划将使得网站在各种设备上均可正常显示和运用,并能习惯乃至还没有发明的设备。与其在今天的技能范围内追赶和规划,咱们将只为用户规划。
这种就不是过错了, 或许是提交给ChatGPT的字数太少, 上下文信息不足, 导致了ChatGPT的误判
## 过错地点的阶段
第二段
## 过错的理由
文章中过错地将 `inline` 写成了 `inline-flex`。
## 改正过错的办法
将过错的 `inline-flex` 改为正确的 `inline` 即可。正确的句子为:
只需求在 HTML 元素上显式设置 `display` 的值为 `flex` 或 `inline` 即可。
到这儿根本就完成了我最初的想法, 其间最大的问题是ChatGPT的接口太慢了, 大家假如要做这种批量的操作,
一定要先找到速度够快的ChatGPT渠道
这咋了? 这是给我标记成爬虫了吧?
我只爬了大漠教师的一个小册啊,

本文代码库房
码云: gitee.com/yashujs/art…
github: github.com/steelan9199…
Git小技巧
假如你要删去远端的文件夹或许文件, 而且保存本地的文件, 依照这个过程做
1. 把文件myfile添加到 .gitignore
2. 假如是文件, 履行 git rm --cached myfile
3. 假如是文件夹, 履行 git rm --cached myfile -r
4. git commit -m "Remove myfile from remote repository"
5. git push