Skip to content

Commit f7dded5

Browse files
committed
备份 Learnku 话题
1 parent f62dbc9 commit f7dded5

File tree

11 files changed

+327
-7
lines changed

11 files changed

+327
-7
lines changed

.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ APP_NAME=Laravel
22
APP_ENV=local
33
APP_KEY=
44
APP_DEBUG=true
5-
APP_TIMEZONE=UTC
5+
APP_TIMEZONE=Asia/Shanghai
66
APP_URL=http://localhost
77

88
APP_LOCALE=en
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use App\Models\LearnkuTopic;
6+
use Illuminate\Console\Command;
7+
use Illuminate\Support\Facades\Http;
8+
use Illuminate\Support\Str;
9+
use Symfony\Component\DomCrawler\Crawler;
10+
11+
class ImportLearnkuTopics extends Command
12+
{
13+
/**
14+
* The name and signature of the console command.
15+
*
16+
* @var string
17+
*/
18+
protected $signature = 'app:import-learnku-topics';
19+
20+
/**
21+
* The console command description.
22+
*
23+
* @var string
24+
*/
25+
protected $description = '导入我的 learnku.com 话题';
26+
27+
/**
28+
* Execute the console command.
29+
*/
30+
public function handle(): void
31+
{
32+
// https://learnku.com/users/72619/topics
33+
$url = $this->ask('请输入你的 learnku.com 话题列表 URL', 'https://learnku.com/users/72619/topics');
34+
35+
$this->info('正在导入话题列表:' . $url);
36+
37+
$topics = $this->getTopics($url);
38+
39+
$this->info('话题列表导入完毕,共 ' . count($topics) . ' 个话题');
40+
41+
// laravel_session
42+
$laravel_session = $this->ask('请输入你的 learnku.com laravel_session', '形如 eyJp...%3D');
43+
44+
$this->withProgressBar($topics, function ($topic) use ($laravel_session) {
45+
// https://learnku.com/laravel/t/86718
46+
$url = $topic['url'];
47+
$title = $topic['title'];
48+
49+
// Extract id from URL with regex
50+
$id = Str::match('/\d+$/', $url);
51+
52+
$body = $this->getTopicBody($id, $laravel_session);
53+
54+
// Save to database
55+
LearnkuTopic::updateOrCreate(['url' => $url], [
56+
'title' => $title,
57+
'body' => $body,
58+
]);
59+
});
60+
}
61+
62+
private function getTopics(string $url, int $page = 1): array
63+
{
64+
$response = Http::get($url, ['page' => $page])->throw();
65+
66+
$crawler = new Crawler($response->body());
67+
68+
// Select all topics via .blog-article-list a.title
69+
$topics = $crawler->filter('.blog-article-list a.title')->each(function (Crawler $node) {
70+
return [
71+
'url' => $node->attr('href'),
72+
'title' => $node->text(),
73+
];
74+
});
75+
76+
// <a class="page-link" href="https://learnku.com/users/72619/topics?page=2" rel="next" aria-label="下一页 »">›</a>
77+
// <span class="page-link" aria-hidden="true">›</span>
78+
$nextPage = $crawler->filter('a.page-link[rel="next"]');
79+
if ($nextPage->count()) {
80+
$topics = array_merge($topics, $this->getTopics($url, $page + 1));
81+
}
82+
83+
return $topics;
84+
}
85+
86+
private function getTopicBody(string $id, string $laravel_session): string
87+
{
88+
// https://learnku.com/topics/86718/edit
89+
$url = "https://learnku.com/topics/$id/edit";
90+
91+
// Get markdown from textarea#body-field
92+
$response = Http::withHeader('Cookie', "laravel_session=$laravel_session")->get($url)->throw();
93+
$crawler = new Crawler($response->body());
94+
return $crawler->filter('textarea#body-field')->html();
95+
}
96+
}

app/Models/LearnkuTopic.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
namespace App\Models;
44

5-
use Illuminate\Database\Eloquent\Factories\HasFactory;
65
use Illuminate\Database\Eloquent\Model;
76

87
class LearnkuTopic extends Model
98
{
10-
use HasFactory;
9+
protected $fillable = ['url', 'title', 'body'];
1110
}

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"require": {
88
"php": "^8.2",
99
"laravel/framework": "^11.9",
10-
"laravel/tinker": "^2.9"
10+
"laravel/tinker": "^2.9",
11+
"symfony/dom-crawler": "^7.1"
1112
},
1213
"require-dev": {
1314
"fakerphp/faker": "^1.23",

composer.lock

Lines changed: 135 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

database/migrations/2024_09_03_073601_create_learnku_topics_table.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ public function up(): void
1414
Schema::create('learnku_topics', function (Blueprint $table) {
1515
$table->id();
1616
// Add url, title, body
17+
$table->string('url')->unique();
18+
$table->string('title');
19+
$table->text('body');
1720
$table->timestamps();
1821
});
1922
}

package-lock.json

Lines changed: 47 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
},
88
"devDependencies": {
99
"@tailwindcss/forms": "^0.5.2",
10+
"@tailwindcss/typography": "^0.5.15",
1011
"alpinejs": "^3.4.2",
1112
"autoprefixer": "^10.4.2",
1213
"axios": "^1.6.4",

0 commit comments

Comments
 (0)