dms-scrape 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/launch.json +1 -1
- package/README.md +51 -32
- package/index.mjs +0 -6
- package/lib/determineCategory.mjs +18 -0
- package/lib/filterContent.mjs +11 -4
- package/lib/justScrape.mjs +20 -11
- package/lib/processHTML.mjs +5 -2
- package/package.json +1 -1
- package/sources/T1/UDNMoney.mjs +10 -3
- package/sources/T2/LTN3C.mjs +2 -1
- package/sources/T2/LTNEC.mjs +2 -2
- package/sources/T2/UDN.mjs +4 -7
- package/sources/T4/CNA.mjs +33 -0
- package/sources/{T3 → T4}/ETDAY.mjs +3 -5
- package/sources/T4/TAISOUNDS.mjs +21 -0
- package/test.mjs +33 -0
- package/sources/T4/TAISOUNDS(unfinished).mjs +0 -9
- /package/sources/{T1 → T2}/CHINATIMES.mjs +0 -0
package/.vscode/launch.json
CHANGED
package/README.md
CHANGED
|
@@ -2,45 +2,64 @@
|
|
|
2
2
|
|
|
3
3
|
## Currently supported sources
|
|
4
4
|
### T1
|
|
5
|
-
- [x]
|
|
6
|
-
- [ ]
|
|
7
|
-
- [x]
|
|
5
|
+
- [x] 電子時報*
|
|
6
|
+
- [ ] 工商時報*
|
|
7
|
+
- [x] 經濟日報 (UDNMoney)
|
|
8
|
+
|
|
8
9
|
### T2
|
|
9
|
-
- [x]
|
|
10
|
-
- [x]
|
|
11
|
-
- [x]
|
|
12
|
-
- [ ]
|
|
10
|
+
- [x] 自由時報 3C
|
|
11
|
+
- [x] 自由時報
|
|
12
|
+
- [x] 聯合報
|
|
13
|
+
- [ ] 聯合晚報
|
|
14
|
+
- [ ] 中國時報*
|
|
15
|
+
- [ ] 時報資訊
|
|
16
|
+
- [ ] 商業週刊
|
|
17
|
+
- [ ] 壹蘋新聞網
|
|
18
|
+
|
|
13
19
|
### T3 電視台
|
|
14
|
-
- [ ] ETtoday
|
|
15
20
|
- [ ] 三立
|
|
21
|
+
- [ ] 華視
|
|
22
|
+
- [ ] 三立新聞台
|
|
23
|
+
- [ ] 東森新聞
|
|
24
|
+
- [ ] 民視新聞網
|
|
25
|
+
- [ ] TVBS
|
|
26
|
+
- [ ] 非凡新聞
|
|
27
|
+
|
|
16
28
|
### T4
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
29
|
+
- [x] 中央社
|
|
30
|
+
- [x] 太報
|
|
31
|
+
- [x] ETDAY ETtoday
|
|
32
|
+
- [ ] cw
|
|
33
|
+
|
|
19
34
|
### T5
|
|
20
35
|
- [x] Mashdigi
|
|
21
36
|
- [x] Cool3c
|
|
22
37
|
- [x] ePrice
|
|
23
|
-
- [x] Sogi
|
|
38
|
+
- [x] Sogi 手機王
|
|
24
39
|
- [ ] TechOrange*
|
|
25
|
-
- [x] KOCPC
|
|
26
|
-
- [x] TechNews
|
|
27
|
-
- [ ] TechBang
|
|
28
|
-
- [
|
|
29
|
-
|
|
30
|
-
|
|
40
|
+
- [x] KOCPC 電腦王阿達
|
|
41
|
+
- [x] TechNews 科技新報
|
|
42
|
+
- [ ] TechBang T客邦
|
|
43
|
+
- [x] XFastest minor bug
|
|
44
|
+
- [ ] 鉅亨網
|
|
45
|
+
- [ ] 聯合新聞網?
|
|
46
|
+
- [ ] 點子生活
|
|
47
|
+
- [ ] 智慧電子解決方案設計平台
|
|
48
|
+
- [ ] Inside
|
|
49
|
+
- [ ] Engadget
|
|
50
|
+
- [ ] 電獺少女
|
|
51
|
+
- [ ] CTIMES
|
|
52
|
+
- [ ] 新唐人亞太台
|
|
53
|
+
- [ ] 新通訊元件雜誌
|
|
54
|
+
- [ ] 中時電子報
|
|
55
|
+
- [ ] 新電子
|
|
56
|
+
- [ ] CTWant (陳柔蓁)
|
|
57
|
+
- [ ] 數位時代
|
|
58
|
+
- [ ] lpcomment
|
|
59
|
+
- [ ] 2cm
|
|
60
|
+
- [ ] techudn
|
|
31
61
|
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
- bnext
|
|
37
|
-
- saydigi
|
|
38
|
-
- inside
|
|
39
|
-
- lpcomment
|
|
40
|
-
- techudnc
|
|
41
|
-
- ctimes
|
|
42
|
-
- ctwant
|
|
43
|
-
- cnyes
|
|
44
|
-
- moneydj
|
|
45
|
-
- 2cm
|
|
46
|
-
- investor
|
|
62
|
+
### T6 財經媒體
|
|
63
|
+
- [ ] 財訊雙週刊
|
|
64
|
+
- [ ] 財訊快報
|
|
65
|
+
- [ ] MoneyDJ
|
package/index.mjs
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function determineCategory(title) {
|
|
2
|
+
switch (true) {
|
|
3
|
+
case title.includes("高通"):
|
|
4
|
+
return "Qualcomm相關新聞";
|
|
5
|
+
|
|
6
|
+
case title.includes("聯發科"):
|
|
7
|
+
return "MediaTek相關新聞";
|
|
8
|
+
|
|
9
|
+
case title.includes("5G"):
|
|
10
|
+
return "無線通訊市場";
|
|
11
|
+
|
|
12
|
+
case title.includes("OPPO") || title.includes("PC"):
|
|
13
|
+
return "智慧型手機/消費性電子產品";
|
|
14
|
+
|
|
15
|
+
default:
|
|
16
|
+
return "其他業界重要訊息";
|
|
17
|
+
}
|
|
18
|
+
}
|
package/lib/filterContent.mjs
CHANGED
|
@@ -8,7 +8,6 @@ export function filterContent(inputArray) {
|
|
|
8
8
|
item !== "《你可能還想看》" &&
|
|
9
9
|
!item.includes("請繼續往下閱讀...") &&
|
|
10
10
|
!item.startsWith("(") &&
|
|
11
|
-
!item.startsWith("(") &&
|
|
12
11
|
!item.startsWith("不用抽") &&
|
|
13
12
|
!item.includes("核稿編輯") &&
|
|
14
13
|
!item.startsWith("記者") &&
|
|
@@ -25,12 +24,20 @@ export function filterContent(inputArray) {
|
|
|
25
24
|
!item.includes("資料來源:") &&
|
|
26
25
|
!item.includes(" ") &&
|
|
27
26
|
!item.includes("上傳") &&
|
|
28
|
-
!item.includes("消息來源") &&
|
|
29
|
-
!item.includes(".jpg") &&
|
|
27
|
+
!item.includes("消息來源") &&
|
|
28
|
+
!item.includes(".jpg") &&
|
|
30
29
|
!item.startsWith("(") &&
|
|
31
30
|
!item.includes("下載附件") &&
|
|
32
31
|
!item.includes("保存到相冊") &&
|
|
33
|
-
!item.includes(".png")
|
|
32
|
+
!item.includes(".png") &&
|
|
33
|
+
!item.includes(",請點選") &&
|
|
34
|
+
!item.includes(",請造訪") &&
|
|
35
|
+
!item.startsWith("。") &&
|
|
36
|
+
!item.includes("其他因素不同而產生差異") &&
|
|
37
|
+
!item.startsWith("此處") &&
|
|
38
|
+
!item.length <= 2 &&
|
|
39
|
+
!item.includes("中央社「一手新聞」 app") &&
|
|
40
|
+
!item.includes("本網站之文字、圖片及影音")
|
|
34
41
|
);
|
|
35
42
|
inputArray = inputArray.map((str) => str.replace(/<\/?[^>]+(>|$)/g, ""));
|
|
36
43
|
inputArray = inputArray.map((line) => line.trim());
|
package/lib/justScrape.mjs
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import { processHTML } from "./processHTML.mjs";
|
|
2
2
|
import { filterContent } from "./filterContent.mjs";
|
|
3
|
+
import { determineCategory } from "./determineCategory.mjs";
|
|
3
4
|
export function justScrape(link, html) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
try {
|
|
6
|
+
var scrapedContent = processHTML(link, html);
|
|
7
|
+
scrapedContent["content"]
|
|
8
|
+
? (scrapedContent["content"] = filterContent(scrapedContent["content"]))
|
|
9
|
+
: "";
|
|
10
|
+
|
|
11
|
+
Array.isArray(scrapedContent["author"])
|
|
12
|
+
? (scrapedContent["author"] = scrapedContent["author"].toString())
|
|
13
|
+
: "";
|
|
14
|
+
Array.isArray(scrapedContent["date"])
|
|
15
|
+
? (scrapedContent["date"] = scrapedContent["date"].toString())
|
|
16
|
+
: "";
|
|
17
|
+
scrapedContent["category"] = determineCategory(scrapedContent["title"])
|
|
18
|
+
scrapedContent["url"] = link;
|
|
19
|
+
return scrapedContent;
|
|
20
|
+
} catch (error) {
|
|
21
|
+
return error;
|
|
22
|
+
}
|
|
23
|
+
}
|
package/lib/processHTML.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { LTN3C } from "../sources/T2/LTN3C.mjs";
|
|
|
2
2
|
import { LTNEC } from "../sources/T2/LTNEC.mjs";
|
|
3
3
|
import { UDN } from "../sources/T2/UDN.mjs";
|
|
4
4
|
import { UDNMoney } from "../sources/T1/UDNMoney.mjs";
|
|
5
|
-
import { ETDAY } from "../sources/
|
|
5
|
+
import { ETDAY } from "../sources/T4/ETDAY.mjs";
|
|
6
6
|
import { EPRICE } from "../sources/T5/EPRICE.mjs";
|
|
7
7
|
import { COOL3C } from "../sources/T5/COOL3C.mjs";
|
|
8
8
|
import { MASHDIGI } from "../sources/T5/MASHDIGI.mjs";
|
|
@@ -12,8 +12,9 @@ import { TECHORANGE } from "../sources/T5/TECHORANGE.mjs";
|
|
|
12
12
|
import { DIGITIMES } from "../sources/T1/DIGITIMES.mjs";
|
|
13
13
|
import { KOCPC } from "../sources/T5/KOCPC.mjs";
|
|
14
14
|
import { XF } from "../sources/T5/XF.mjs";
|
|
15
|
-
import { TAISOUNDS } from "../sources/T4/TAISOUNDS
|
|
15
|
+
import { TAISOUNDS } from "../sources/T4/TAISOUNDS.mjs";
|
|
16
16
|
import { TECHNEWS } from "../sources/T5/TECHNEWS.mjs";
|
|
17
|
+
import { CNA } from "../sources/T4/CNA.mjs";
|
|
17
18
|
|
|
18
19
|
function determineSource(link) {
|
|
19
20
|
if (link.includes("3c.ltn")) {
|
|
@@ -46,6 +47,8 @@ function determineSource(link) {
|
|
|
46
47
|
return TAISOUNDS
|
|
47
48
|
} else if (link.includes("technews")) {
|
|
48
49
|
return TECHNEWS
|
|
50
|
+
} else if (link.includes("cna")) {
|
|
51
|
+
return CNA
|
|
49
52
|
}
|
|
50
53
|
}
|
|
51
54
|
|
package/package.json
CHANGED
package/sources/T1/UDNMoney.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
2
1
|
export function UDNMoney($) {
|
|
3
2
|
const data = $.extract({
|
|
4
|
-
|
|
3
|
+
title: "h1#story_art_title",
|
|
5
4
|
date: [
|
|
6
5
|
{
|
|
7
6
|
selector: "time.article-body__time",
|
|
@@ -24,11 +23,17 @@ export function UDNMoney($) {
|
|
|
24
23
|
{
|
|
25
24
|
selector: "section.article-body__editor p",
|
|
26
25
|
value: (el, key) => {
|
|
26
|
+
const sampleKey = this.findIndex(item => item.includes("延伸閱讀"))
|
|
27
27
|
if (!$(el).text().trim() == "") {
|
|
28
|
-
|
|
28
|
+
const sample = $(el)
|
|
29
29
|
.text()
|
|
30
30
|
.replace(/\$\(.*/s, "")
|
|
31
31
|
.trim();
|
|
32
|
+
|
|
33
|
+
if (key < sampleKey) {
|
|
34
|
+
return sample;
|
|
35
|
+
}
|
|
36
|
+
|
|
32
37
|
}
|
|
33
38
|
},
|
|
34
39
|
},
|
|
@@ -37,3 +42,5 @@ export function UDNMoney($) {
|
|
|
37
42
|
data["source"] = "經濟日報";
|
|
38
43
|
return data;
|
|
39
44
|
}
|
|
45
|
+
|
|
46
|
+
//minor unresolved additional headlines
|
package/sources/T2/LTN3C.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export function LTN3C($) {
|
|
2
2
|
const data = $.extract({
|
|
3
|
-
|
|
3
|
+
title: "div.whitecon.borderline.boxTitle.boxText h1",
|
|
4
4
|
date: [
|
|
5
5
|
{
|
|
6
6
|
selector: "span.time",
|
|
@@ -29,5 +29,6 @@ export function LTN3C($) {
|
|
|
29
29
|
},
|
|
30
30
|
],
|
|
31
31
|
});
|
|
32
|
+
data["source"] = "自由時報"
|
|
32
33
|
return data;
|
|
33
34
|
}
|
package/sources/T2/LTNEC.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export function LTNEC($) {
|
|
2
2
|
const data = $.extract({
|
|
3
|
-
|
|
3
|
+
title: "div.whitecon.boxTitle.boxText h1",
|
|
4
4
|
date: [
|
|
5
5
|
{
|
|
6
6
|
selector: "span.time:nth-of-type(1)",
|
|
@@ -35,6 +35,6 @@ export function LTNEC($) {
|
|
|
35
35
|
},
|
|
36
36
|
],
|
|
37
37
|
});
|
|
38
|
-
|
|
38
|
+
data["source"] = "自由時報"
|
|
39
39
|
return data;
|
|
40
40
|
}
|
package/sources/T2/UDN.mjs
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
export function UDN($) {
|
|
2
2
|
const data = $.extract({
|
|
3
|
-
|
|
3
|
+
title: "h1.article-content__title",
|
|
4
4
|
date: [
|
|
5
5
|
{
|
|
6
6
|
selector: "time.article-content__time",
|
|
7
7
|
value: (el, key) => {
|
|
8
|
-
const data = $(el).text().replace(/\//g, "-")
|
|
9
|
-
.slice(0, 10);
|
|
8
|
+
const data = $(el).text().replace(/\//g, "-").slice(0, 10);
|
|
10
9
|
return data;
|
|
11
10
|
},
|
|
12
11
|
},
|
|
@@ -16,14 +15,12 @@ export function UDN($) {
|
|
|
16
15
|
{
|
|
17
16
|
selector: "section.article-content__editor p",
|
|
18
17
|
value: (el, key) => {
|
|
19
|
-
const text = $(el)
|
|
20
|
-
.text()
|
|
21
|
-
.trim();
|
|
18
|
+
const text = $(el).text().trim();
|
|
22
19
|
return text;
|
|
23
20
|
},
|
|
24
21
|
},
|
|
25
22
|
],
|
|
26
23
|
});
|
|
27
|
-
|
|
24
|
+
data["source"] = "聯合報";
|
|
28
25
|
return data;
|
|
29
26
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export function CNA($) {
|
|
2
|
+
const data = $.extract({
|
|
3
|
+
content: [
|
|
4
|
+
{
|
|
5
|
+
selector: "div.paragraph > p",
|
|
6
|
+
value: (el, key) => {
|
|
7
|
+
return $(el).text();
|
|
8
|
+
},
|
|
9
|
+
},
|
|
10
|
+
],
|
|
11
|
+
author: [
|
|
12
|
+
{
|
|
13
|
+
selector: "div.paragraph > p",
|
|
14
|
+
value: (el, key) => {
|
|
15
|
+
if ( $(el).text().includes("(中央社")) {
|
|
16
|
+
let index = $(el).text().indexOf("記者");
|
|
17
|
+
|
|
18
|
+
// Extract the 3 characters after "記者"
|
|
19
|
+
return $(el)
|
|
20
|
+
.text()
|
|
21
|
+
.substring(index + 2, index + 5);
|
|
22
|
+
// return index
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
});
|
|
28
|
+
data["date"] = $('meta[property="article:published_time"]')
|
|
29
|
+
.attr("content")
|
|
30
|
+
.slice(0, 10);
|
|
31
|
+
data["source"] = "中央社";
|
|
32
|
+
return data;
|
|
33
|
+
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
export function ETDAY(html) {
|
|
3
|
-
const $ = cheerio.load(html);
|
|
1
|
+
export function ETDAY($) {
|
|
4
2
|
const data = $.extract({
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
title: "h1.title",
|
|
4
|
+
date: [
|
|
7
5
|
{
|
|
8
6
|
selector: "time.date",
|
|
9
7
|
value: (el, key) => {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function TAISOUNDS($) {
|
|
2
|
+
const data = $.extract({
|
|
3
|
+
date: [
|
|
4
|
+
{
|
|
5
|
+
selector: "div.publish",
|
|
6
|
+
value: (el, key) => {
|
|
7
|
+
const eachValue = $(el).text().trim();
|
|
8
|
+
if (eachValue !== "") {
|
|
9
|
+
return eachValue.slice(0, 10);
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
|
|
15
|
+
});
|
|
16
|
+
data["title"] = $("div.news-box h1").text();
|
|
17
|
+
data["source"] = "太報";
|
|
18
|
+
data["author"] = $("a[href^='/more/reporternews']").text();
|
|
19
|
+
data["content"] = $("div.news-box-text.border").html().split("\n").filter((item) => item.includes("<br>")).toString().split(/<\/?[^>]+>/).filter((item)=> item != '')
|
|
20
|
+
return data;
|
|
21
|
+
}
|
package/test.mjs
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { dmsScrape } from "./index.mjs";
|
|
2
|
+
|
|
3
|
+
const testLinks = [
|
|
4
|
+
"https://www.cool3c.com/article/202079",
|
|
5
|
+
|
|
6
|
+
"https://www.kocpc.com.tw/archives/563640",
|
|
7
|
+
"https://mashdigi.com/qualcomm-continues-to-launch-the-snapdragon-x-plus-processor-composed-of-8-sets-of-performance-cores-expanding-the-copilot-pc-product-lineup/",
|
|
8
|
+
"https://www.sogi.com.tw/articles/samsung_galaxy_s25_ultra/6262880",
|
|
9
|
+
"https://technews.tw/2024/09/12/snapdragon-8-gen-4-and-dimensity-9400-configuration-unveiled/",
|
|
10
|
+
"https://www.xfastest.com/thread-291944-1-1.html",
|
|
11
|
+
"https://www.ettoday.net/news/20240905/2810968.htm",
|
|
12
|
+
"https://udn.com/news/story/7240/8145957",
|
|
13
|
+
"https://money.udn.com/money/story/5613/8231957",
|
|
14
|
+
"https://3c.ltn.com.tw/news/59270",
|
|
15
|
+
"https://ec.ltn.com.tw/article/breakingnews/4790282",
|
|
16
|
+
"https://www.digitimes.com.tw/tech/dt/n/shwnws.asp?id=0000700414_DTZ3HLET2I9D7N38H02NN",
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const buggedLinks = ["https://www.eprice.com.tw/mobile/talk/4523/5811558/1/"];
|
|
20
|
+
const testLink = [
|
|
21
|
+
"https://www.ettoday.net/news/20240905/2810968.htm",
|
|
22
|
+
];
|
|
23
|
+
async function getTestLinks() {
|
|
24
|
+
var response = [];
|
|
25
|
+
for (const link of testLink) {
|
|
26
|
+
response.push(await dmsScrape("link", link));
|
|
27
|
+
// response = await fetch(link);
|
|
28
|
+
}
|
|
29
|
+
// return await response.text();
|
|
30
|
+
return response;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log(await getTestLinks());
|
|
File without changes
|