pal-crawl 2.2.0 → 2.3.0
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/AGENTS.md +360 -0
- package/README.md +424 -8
- package/dist/config.d.ts +23 -1
- package/dist/config.js +25 -0
- package/dist/config.js.map +1 -1
- package/dist/http-client.d.ts +10 -2
- package/dist/http-client.js +44 -7
- package/dist/http-client.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/likms.d.ts +282 -0
- package/dist/likms.js +409 -21
- package/dist/likms.js.map +1 -1
- package/dist/nsm-compat.d.ts +198 -0
- package/dist/nsm-compat.js +342 -0
- package/dist/nsm-compat.js.map +1 -0
- package/dist/pal.d.ts +7 -3
- package/dist/pal.js.map +1 -1
- package/dist/parser.d.ts +159 -0
- package/dist/parser.js +301 -1
- package/dist/parser.js.map +1 -1
- package/package.json +6 -1
- package/.freebuff/project-id +0 -1
- package/dist/likms.test.d.ts +0 -1
- package/dist/likms.test.js +0 -313
- package/dist/likms.test.js.map +0 -1
- package/dist/pal.test.d.ts +0 -1
- package/dist/pal.test.js +0 -1276
- package/dist/pal.test.js.map +0 -1
package/dist/http-client.js
CHANGED
|
@@ -41,11 +41,42 @@ const https = __importStar(require("https"));
|
|
|
41
41
|
const iconv_lite_1 = __importDefault(require("iconv-lite"));
|
|
42
42
|
class HttpClient {
|
|
43
43
|
constructor(config) {
|
|
44
|
+
/** 응답의 Set-Cookie를 세션 동안 유지하기 위한 간단한 쿠키 저장소 */
|
|
45
|
+
this.cookies = new Map();
|
|
44
46
|
this.userAgent = config.userAgent;
|
|
45
47
|
this.timeout = config.timeout;
|
|
46
48
|
this.retryCount = config.retryCount;
|
|
47
49
|
this.customHeaders = config.customHeaders;
|
|
48
50
|
}
|
|
51
|
+
buildCookieHeader() {
|
|
52
|
+
return Array.from(this.cookies.entries())
|
|
53
|
+
.map(([name, value]) => `${name}=${value}`)
|
|
54
|
+
.join('; ');
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Set-Cookie 헤더를 쿠키 저장소에 반영합니다.
|
|
58
|
+
* 세션 쿠키(JSESSIONID 등)가 필요한 사이트(계류의안 AJAX 등)에서 사용합니다.
|
|
59
|
+
*/
|
|
60
|
+
storeCookies(setCookie) {
|
|
61
|
+
if (!setCookie) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
for (const raw of setCookie) {
|
|
65
|
+
const pair = raw.split(';')[0].trim();
|
|
66
|
+
const separatorIndex = pair.indexOf('=');
|
|
67
|
+
if (separatorIndex <= 0) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const name = pair.slice(0, separatorIndex).trim();
|
|
71
|
+
const value = pair.slice(separatorIndex + 1).trim();
|
|
72
|
+
if (value === '') {
|
|
73
|
+
this.cookies.delete(name);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
this.cookies.set(name, value);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
49
80
|
extractCharset(contentType, body) {
|
|
50
81
|
const contentTypeValue = Array.isArray(contentType)
|
|
51
82
|
? contentType.join(';')
|
|
@@ -100,12 +131,17 @@ class HttpClient {
|
|
|
100
131
|
}
|
|
101
132
|
return body.toString('utf8');
|
|
102
133
|
}
|
|
103
|
-
async makeRequest(url, method = 'GET', body) {
|
|
134
|
+
async makeRequest(url, method = 'GET', body, extraHeaders) {
|
|
104
135
|
return new Promise((resolve, reject) => {
|
|
105
136
|
const headers = {
|
|
106
137
|
'User-Agent': this.userAgent,
|
|
107
138
|
...this.customHeaders,
|
|
139
|
+
...extraHeaders,
|
|
108
140
|
};
|
|
141
|
+
const cookieHeader = this.buildCookieHeader();
|
|
142
|
+
if (cookieHeader) {
|
|
143
|
+
headers['Cookie'] = cookieHeader;
|
|
144
|
+
}
|
|
109
145
|
if (method === 'POST' && body !== undefined) {
|
|
110
146
|
headers['Content-Type'] =
|
|
111
147
|
'application/x-www-form-urlencoded; charset=UTF-8';
|
|
@@ -126,6 +162,7 @@ class HttpClient {
|
|
|
126
162
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
127
163
|
});
|
|
128
164
|
res.on('end', () => {
|
|
165
|
+
this.storeCookies(res.headers['set-cookie']);
|
|
129
166
|
const responseBody = Buffer.concat(chunks);
|
|
130
167
|
resolve(this.decodeBody(responseBody, res.headers['content-type']));
|
|
131
168
|
});
|
|
@@ -144,21 +181,21 @@ class HttpClient {
|
|
|
144
181
|
req.setTimeout(this.timeout);
|
|
145
182
|
});
|
|
146
183
|
}
|
|
147
|
-
async get(url) {
|
|
148
|
-
return this.requestWithRetry(url, 'GET');
|
|
184
|
+
async get(url, headers) {
|
|
185
|
+
return this.requestWithRetry(url, 'GET', undefined, headers);
|
|
149
186
|
}
|
|
150
187
|
/**
|
|
151
188
|
* URL-encoded 본문을 POST로 전송합니다.
|
|
152
189
|
* 국회 의안정보시스템의 일부 조각(_fragment) 엔드포인트는 GET이 아닌 POST만 허용합니다.
|
|
153
190
|
*/
|
|
154
|
-
async post(url, body) {
|
|
155
|
-
return this.requestWithRetry(url, 'POST', body);
|
|
191
|
+
async post(url, body, headers) {
|
|
192
|
+
return this.requestWithRetry(url, 'POST', body, headers);
|
|
156
193
|
}
|
|
157
|
-
async requestWithRetry(url, method, body) {
|
|
194
|
+
async requestWithRetry(url, method, body, headers) {
|
|
158
195
|
let lastError;
|
|
159
196
|
for (let attempt = 1; attempt <= this.retryCount; attempt++) {
|
|
160
197
|
try {
|
|
161
|
-
return await this.makeRequest(url, method, body);
|
|
198
|
+
return await this.makeRequest(url, method, body, headers);
|
|
162
199
|
}
|
|
163
200
|
catch (error) {
|
|
164
201
|
lastError = error;
|
package/dist/http-client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,6CAA+B;AAE/B,4DAA+B;AAS/B,MAAa,UAAU;
|
|
1
|
+
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { ScreenshotBase, PalCrawl, NsmLmSts, type ITableData, type IAttachment, type IContentData, type ISearchResult, type ISearchQuery, type IBulkOptions, type PalCrawlConfig, type ScreenshotOptions, type INsmSearchQuery, type INsmSearchResult, type INsmBillItem, type INsmBillDetail, type INsmAttachment, type NsmProgressStatus, type NsmProposerType, type NsmResolutionStatus, } from './pal';
|
|
2
|
-
export { PalParser, NsmLmStsParser } from './parser';
|
|
3
|
-
export { LikmsCrawler, type LikmsCrawlerConfig } from './likms';
|
|
2
|
+
export { PalParser, NsmLmStsParser, LikmsStateParser, LikmsDetailParser, type ILikmsCommittee, type ILikmsStateBillItem, type ILikmsStateSearchResult, type ILikmsRepresentCandidate, type ILikmsDetailInfo, type ILikmsDocAttachment, } from './parser';
|
|
3
|
+
export { LikmsCrawler, LikmsStateCrawler, type LikmsCrawlerConfig, type LikmsStateCrawlerConfig, type ILikmsStateQuery, type LikmsStateId, type LikmsStateRepresentKind, type LikmsStateProposerKind, type LikmsStateSortOrder, type LikmsStateCmtResult, type LikmsStateJointProposal, } from './likms';
|
|
4
|
+
export { LikmsNsmAdapter, type INsmListCrawler, type INsmDetailCrawler, } from './nsm-compat';
|
|
4
5
|
export { Config } from './config';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Config = exports.LikmsCrawler = exports.NsmLmStsParser = exports.PalParser = exports.NsmLmSts = exports.PalCrawl = exports.ScreenshotBase = void 0;
|
|
3
|
+
exports.Config = exports.LikmsNsmAdapter = exports.LikmsStateCrawler = exports.LikmsCrawler = exports.LikmsDetailParser = exports.LikmsStateParser = exports.NsmLmStsParser = exports.PalParser = exports.NsmLmSts = exports.PalCrawl = exports.ScreenshotBase = void 0;
|
|
4
4
|
var pal_1 = require("./pal");
|
|
5
5
|
Object.defineProperty(exports, "ScreenshotBase", { enumerable: true, get: function () { return pal_1.ScreenshotBase; } });
|
|
6
6
|
Object.defineProperty(exports, "PalCrawl", { enumerable: true, get: function () { return pal_1.PalCrawl; } });
|
|
@@ -8,8 +8,13 @@ Object.defineProperty(exports, "NsmLmSts", { enumerable: true, get: function ()
|
|
|
8
8
|
var parser_1 = require("./parser");
|
|
9
9
|
Object.defineProperty(exports, "PalParser", { enumerable: true, get: function () { return parser_1.PalParser; } });
|
|
10
10
|
Object.defineProperty(exports, "NsmLmStsParser", { enumerable: true, get: function () { return parser_1.NsmLmStsParser; } });
|
|
11
|
+
Object.defineProperty(exports, "LikmsStateParser", { enumerable: true, get: function () { return parser_1.LikmsStateParser; } });
|
|
12
|
+
Object.defineProperty(exports, "LikmsDetailParser", { enumerable: true, get: function () { return parser_1.LikmsDetailParser; } });
|
|
11
13
|
var likms_1 = require("./likms");
|
|
12
14
|
Object.defineProperty(exports, "LikmsCrawler", { enumerable: true, get: function () { return likms_1.LikmsCrawler; } });
|
|
15
|
+
Object.defineProperty(exports, "LikmsStateCrawler", { enumerable: true, get: function () { return likms_1.LikmsStateCrawler; } });
|
|
16
|
+
var nsm_compat_1 = require("./nsm-compat");
|
|
17
|
+
Object.defineProperty(exports, "LikmsNsmAdapter", { enumerable: true, get: function () { return nsm_compat_1.LikmsNsmAdapter; } });
|
|
13
18
|
var config_1 = require("./config");
|
|
14
19
|
Object.defineProperty(exports, "Config", { enumerable: true, get: function () { return config_1.Config; } });
|
|
15
20
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,6BAoBe;AAnBb,qGAAA,cAAc,OAAA;AACd,+FAAA,QAAQ,OAAA;AACR,+FAAA,QAAQ,OAAA;AAkBV,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,6BAoBe;AAnBb,qGAAA,cAAc,OAAA;AACd,+FAAA,QAAQ,OAAA;AACR,+FAAA,QAAQ,OAAA;AAkBV,mCAWkB;AAVhB,mGAAA,SAAS,OAAA;AACT,wGAAA,cAAc,OAAA;AACd,0GAAA,gBAAgB,OAAA;AAChB,2GAAA,iBAAiB,OAAA;AAQnB,iCAYiB;AAXf,qGAAA,YAAY,OAAA;AACZ,0GAAA,iBAAiB,OAAA;AAWnB,2CAIsB;AAHpB,6GAAA,eAAe,OAAA;AAIjB,mCAAkC;AAAzB,gGAAA,MAAM,OAAA"}
|
package/dist/likms.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { IBulkOptions } from './pal';
|
|
2
|
+
import { type ILikmsCommittee, type ILikmsRepresentCandidate, type ILikmsStateBillItem, type ILikmsStateSearchResult } from './parser';
|
|
1
3
|
export interface LikmsCrawlerConfig {
|
|
2
4
|
userAgent?: string;
|
|
3
5
|
timeout?: number;
|
|
@@ -22,7 +24,14 @@ export interface LikmsCrawlerConfig {
|
|
|
22
24
|
*/
|
|
23
25
|
export declare class LikmsCrawler {
|
|
24
26
|
private readonly httpClient;
|
|
27
|
+
private readonly detailParser;
|
|
25
28
|
constructor(config?: LikmsCrawlerConfig);
|
|
29
|
+
/**
|
|
30
|
+
* 의안번호(예: `2221883`)로 billId를 조회합니다 (`/bi/common/findBillDetail.do`).
|
|
31
|
+
* 의안상세 페이지는 billId만 받으므로, 목록의 의안번호밖에 없을 때 사용합니다.
|
|
32
|
+
* 존재하지 않거나 응답이 JSON이 아니면 `null`을 반환합니다(네트워크 오류는 전파).
|
|
33
|
+
*/
|
|
34
|
+
resolveBillId(billNo: string): Promise<string | null>;
|
|
26
35
|
private buildDetailPageUrl;
|
|
27
36
|
/** 의안상세 페이지 HTML을 반환합니다. */
|
|
28
37
|
getDetailPageHTML(billId: string): Promise<string>;
|
|
@@ -43,3 +52,276 @@ export declare class LikmsCrawler {
|
|
|
43
52
|
*/
|
|
44
53
|
getProposalReason(billId: string): Promise<string | null>;
|
|
45
54
|
}
|
|
55
|
+
export interface LikmsStateCrawlerConfig {
|
|
56
|
+
userAgent?: string;
|
|
57
|
+
timeout?: number;
|
|
58
|
+
retryCount?: number;
|
|
59
|
+
customHeaders?: Record<string, string>;
|
|
60
|
+
/**
|
|
61
|
+
* 목록의 `hasProposalReason` 법안의 제안이유를 의안상세에서 조회해 채울지 여부
|
|
62
|
+
* (기본값: false).
|
|
63
|
+
*
|
|
64
|
+
* 건당 2회(상세 페이지 + billInfo.do) 요청이 추가되므로 기본적으로 꺼져 있다.
|
|
65
|
+
* 켜면 `search` / `getPage` / `getAllPages`가 자동으로 보정하며, 실패한 건은
|
|
66
|
+
* 기존 값(`null`)을 유지하고 오류를 던지지 않는다.
|
|
67
|
+
* 보정 속도를 조절하려면 `hydrateProposalReasons(items, options)`를 직접 호출한다.
|
|
68
|
+
*/
|
|
69
|
+
hydrateProposalReason?: boolean;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 의안현황 페이지 구분. 계류의안(`mooring`)이 기본값이며 이 크롤러의 주 대상입니다.
|
|
73
|
+
* - mooring: 계류의안
|
|
74
|
+
* - finish: 처리의안
|
|
75
|
+
* - suggest: 위원회안(대안)
|
|
76
|
+
* - beforePropose: 본회의 부의안건
|
|
77
|
+
*/
|
|
78
|
+
export type LikmsStateId = 'mooring' | 'finish' | 'suggest' | 'beforePropose';
|
|
79
|
+
/**
|
|
80
|
+
* 발의구분 코드
|
|
81
|
+
* - REPR: 대표발의
|
|
82
|
+
* - SING: 1인발의
|
|
83
|
+
* - COMM: 공동발의
|
|
84
|
+
* - 전체
|
|
85
|
+
*/
|
|
86
|
+
export type LikmsStateRepresentKind = 'REPR' | 'SING' | 'COMM' | '전체';
|
|
87
|
+
/** 정렬 방향 */
|
|
88
|
+
export type LikmsStateSortOrder = 'ASC' | 'DESC';
|
|
89
|
+
/**
|
|
90
|
+
* 제안자구분 코드 (`proposerKind`)
|
|
91
|
+
* - MEMASEMBY: 의원
|
|
92
|
+
* - GOV: 정부
|
|
93
|
+
* - CHRPR: 위원장
|
|
94
|
+
* - CHRM: 의장
|
|
95
|
+
* - PRESIDENT: 대통령
|
|
96
|
+
* - ETC: 기타
|
|
97
|
+
*/
|
|
98
|
+
export type LikmsStateProposerKind = 'MEMASEMBY' | 'GOV' | 'CHRPR' | 'CHRM' | 'PRESIDENT' | 'ETC' | '전체';
|
|
99
|
+
/**
|
|
100
|
+
* 소관위 처리결과 코드 (`cmtResultCd`). 사이트 검색 폼의 선택지와 같은 값이다(실측 2026-10-13).
|
|
101
|
+
* - PRC_0000: 계류
|
|
102
|
+
* - PRC_0011: 폐기
|
|
103
|
+
* - PRC_0013: 가결
|
|
104
|
+
* - PRC_0014: 부결
|
|
105
|
+
*
|
|
106
|
+
* 소관위원회의 처리결과이므로 NSM `rslRsltNmR`(본회의 의결현황)과는 축이 다르다.
|
|
107
|
+
*/
|
|
108
|
+
export type LikmsStateCmtResult = 'PRC_0000' | 'PRC_0011' | 'PRC_0013' | 'PRC_0014';
|
|
109
|
+
/** 공동발의 여부 (`jntPrpslYn`). 미지정이면 사이트 기본값 '전체'로 조회된다. */
|
|
110
|
+
export type LikmsStateJointProposal = 'Y' | 'N';
|
|
111
|
+
export interface ILikmsStateQuery {
|
|
112
|
+
pageIndex?: number;
|
|
113
|
+
/** 페이지당 건수 (`rows`, 기본값 50) */
|
|
114
|
+
pageSize?: number;
|
|
115
|
+
/** 의안현황 페이지 구분 (기본값: "mooring") */
|
|
116
|
+
stateId?: LikmsStateId;
|
|
117
|
+
/** 탭 구분 (계류의안 기본값: "all") */
|
|
118
|
+
stateDtlDivCd?: string;
|
|
119
|
+
/** 의안명 */
|
|
120
|
+
billNm?: string;
|
|
121
|
+
/** 의안번호 */
|
|
122
|
+
billNo?: string;
|
|
123
|
+
/**
|
|
124
|
+
* 발의구분 (대표발의/1인발의/공동발의).
|
|
125
|
+
* 발의자 필터는 `representId`와 이 값이 **둘 다** 있어야 서버가 적용한다
|
|
126
|
+
* (`representId`만 주면 무시되므로 '전체'로 자동 보정된다).
|
|
127
|
+
*/
|
|
128
|
+
representKindCd?: LikmsStateRepresentKind;
|
|
129
|
+
/** 제안자구분 (정부/의원/위원장 등) */
|
|
130
|
+
proposerKind?: LikmsStateProposerKind;
|
|
131
|
+
/**
|
|
132
|
+
* 발의자 ID(의원 ID). 서버 필터는 이 값만 확정적으로 받는다 — 이름은 받지 않으므로
|
|
133
|
+
* 크롤러가 이름을 해석하지 않는다. 이름밖에 모를 때는 `findRepresentCandidates(name)`로
|
|
134
|
+
* 사이트가 주는 후보를 확인해 그 `membId`를 여기에 넣는다.
|
|
135
|
+
* (`representKindCd`와 함께 보내야 필터가 동작한다.)
|
|
136
|
+
*/
|
|
137
|
+
representId?: string;
|
|
138
|
+
/**
|
|
139
|
+
* 소관위원회 코드. 이름이 아니라 코드를 받으므로 이름밖에 모를 때는
|
|
140
|
+
* `findCommittees(ageFrom, ageTo)`로 코드를 확인해 여기에 넣는다.
|
|
141
|
+
*/
|
|
142
|
+
ageCmtId?: string;
|
|
143
|
+
/**
|
|
144
|
+
* 소관위 처리결과(계류/가결/부결/폐기). 계류안만 보려면 `'PRC_0000'`.
|
|
145
|
+
* 계류의안 탭에서도 처리된 건이 섞여 나오므로 좁힐 때 쓴다.
|
|
146
|
+
*/
|
|
147
|
+
cmtResultCd?: LikmsStateCmtResult;
|
|
148
|
+
/** 공동발의 여부. `'전체'`는 값을 보내지 않는 것과 같다. */
|
|
149
|
+
jntPrpslYn?: LikmsStateJointProposal;
|
|
150
|
+
/** 제안대수 시작 (예: "22") */
|
|
151
|
+
ageFrom?: string | number;
|
|
152
|
+
/** 제안대수 끝 */
|
|
153
|
+
ageTo?: string | number;
|
|
154
|
+
/** 의안종류 (예: "법률안") */
|
|
155
|
+
billKind?: string;
|
|
156
|
+
/** 정렬 컬럼 (예: "billNo", "billName", "proposeDt") */
|
|
157
|
+
listOrd?: string;
|
|
158
|
+
/** 정렬 방향 */
|
|
159
|
+
ordCd?: LikmsStateSortOrder;
|
|
160
|
+
/**
|
|
161
|
+
* 제안일자 시작 (YYYY-MM-DD). 서버는 `toPropDt`와 **함께** 줄 때만 적용한다
|
|
162
|
+
* (한쪽만 보내면 무시된다).
|
|
163
|
+
*/
|
|
164
|
+
fromPropDt?: string;
|
|
165
|
+
/** 제안일자 종료 (YYYY-MM-DD). `fromPropDt`와 함께 줘야 적용된다. */
|
|
166
|
+
toPropDt?: string;
|
|
167
|
+
/** 결과 내 재검색어 */
|
|
168
|
+
nmReSchText?: string;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* 국회 의안정보시스템(likms.assembly.go.kr) 의안현황 > 계류의안 크롤러.
|
|
172
|
+
*
|
|
173
|
+
* 국민참여입법센터(NsmLmSts)의 계류 법안 조회를 대체할 수 있으며, 동일한
|
|
174
|
+
* `search` / `getPage` / `getAllPages` 구조를 제공합니다.
|
|
175
|
+
*
|
|
176
|
+
* 실제 흐름 (billState.js, biInit.js 기준):
|
|
177
|
+
* 1. GET /bill/bi/bill/state/mooringBillPage.do?stateId=mooring
|
|
178
|
+
* → 세션 쿠키(JSESSIONID)와 <meta name="_csrf"> 토큰, #form 숨김 필드 확보
|
|
179
|
+
* 2. POST /bill/bi/bill/state/searchBillStatePaging.do
|
|
180
|
+
* → 헤더 X-CSRF-TOKEN: <토큰>, 본문은 1에서 얻은 숨김 필드 + 요청 조건
|
|
181
|
+
* 3. 응답은 <div id="state-list"> 목록 조각 HTML (JSON 아님)
|
|
182
|
+
* - 총 건수/페이지: #pager_count_text, #pager_pages_text 숨김 input
|
|
183
|
+
*
|
|
184
|
+
* CSRF 토큰은 페이지 로드 시 한 번 발급되어 세션 동안 유지되므로, 첫 요청에서만
|
|
185
|
+
* 페이지를 조회해 토큰·폼 필드를 캐시합니다(만료 시 1회 자동 재발급).
|
|
186
|
+
*
|
|
187
|
+
* 본문을 페이지 숨김 필드로 시작하는 이유: 브라우저가 폼을 직렬화해 보내는 방식과
|
|
188
|
+
* 같아야 발의자(`representId`) 필터가 동작한다. 최소 파라미터만 보내면
|
|
189
|
+
* 서버가 발의자 조건을 조용히 무시한다.
|
|
190
|
+
*
|
|
191
|
+
* 발의자 **이름**은 서버도 크롤러도 해석하지 않는다(이름만으로는 어느 의원인지
|
|
192
|
+
* 확정할 수 없다). 이름밖에 없으면 `findRepresentCandidates()`로 사이트가 제시하는
|
|
193
|
+
* 후보를 보고 호출부가 `membId`를 고르는 것이 유일한 경로다.
|
|
194
|
+
*/
|
|
195
|
+
export declare class LikmsStateCrawler {
|
|
196
|
+
private readonly httpClient;
|
|
197
|
+
private readonly parser;
|
|
198
|
+
/** 제안이유 보정용 의안상세 크롤러 (billId 단위 조회) */
|
|
199
|
+
private readonly detailCrawler;
|
|
200
|
+
private readonly hydrateProposalReason;
|
|
201
|
+
/** 제안이유 보정 기본 동시 요청 수 (1 = 순차) */
|
|
202
|
+
private readonly hydrateConcurrency;
|
|
203
|
+
/** 제안이유 보정 기본 요청 간 지연(ms) — 대상 사이트 부하 방지 */
|
|
204
|
+
private readonly hydrateDelayMs;
|
|
205
|
+
private session;
|
|
206
|
+
constructor(config?: LikmsStateCrawlerConfig);
|
|
207
|
+
private buildStatePageUrl;
|
|
208
|
+
/**
|
|
209
|
+
* 계류의안 페이지 HTML을 반환합니다.
|
|
210
|
+
* 세션 쿠키와 CSRF 토큰을 확보하는 진입점으로 사용됩니다.
|
|
211
|
+
*/
|
|
212
|
+
getStatePageHTML(stateId?: LikmsStateId): Promise<string>;
|
|
213
|
+
/** 페이지의 <meta name="_csrf"> 값에서 CSRF 토큰을 추출합니다. */
|
|
214
|
+
extractCsrfToken(html: string): string | null;
|
|
215
|
+
/**
|
|
216
|
+
* 페이지 `#form`의 숨김 필드를 객체로 추출합니다(CSRF 토큰 제외).
|
|
217
|
+
* 검색 AJAX 본문의 기본값으로 쓰이며, 브라우저가 폼을 직렬화해 보내는 것과 같습니다.
|
|
218
|
+
*/
|
|
219
|
+
parseStateFormParams(html: string): Record<string, string>;
|
|
220
|
+
/**
|
|
221
|
+
* 캐시된 세션(CSRF 토큰·폼 숨김 필드)을 버려 다음 요청에서 다시 발급받도록 합니다.
|
|
222
|
+
*/
|
|
223
|
+
clearSession(): void;
|
|
224
|
+
private ensureSession;
|
|
225
|
+
private buildSearchBody;
|
|
226
|
+
/**
|
|
227
|
+
* 발의자명으로 **후보 목록**을 조회합니다 (`/bi/popup/selSameNmMemb.do`).
|
|
228
|
+
*
|
|
229
|
+
* 서버 검색 필터는 의원 ID(`representId`)만 받으므로, 이름밖에 모를 때 이 메서드로
|
|
230
|
+
* 사이트가 제시하는 후보(의원 ID·대수·한자명·정당명)를 보고 호출부가 고른다.
|
|
231
|
+
* 이름 하나를 ID로 자동 확정하지 않는다 — 같은 이름이 여러 대수에 있거나
|
|
232
|
+
* **같은 대수에** 둘 이상일 수 있어(예: 21대 이수진 2인) 크롤러가 정할 수 없다.
|
|
233
|
+
*
|
|
234
|
+
* - 명단에 없으면 빈 배열
|
|
235
|
+
* - `ageFrom`/`ageTo`는 서버가 필수로 받는다(없으면 400) → 기본값은 전체 범위(`01`–`99`)
|
|
236
|
+
* - GET이라 CSRF 토큰·세션이 필요 없다(실측: 쿠키 없이도 200)
|
|
237
|
+
*
|
|
238
|
+
* - 명단에 없으면 빈 배열
|
|
239
|
+
* - `ageFrom`/`ageTo`는 서버가 필수로 받는다(없으면 400) → 기본값은 전체 범위(`01`–`99`)
|
|
240
|
+
* - GET이라 CSRF 토큰·세션이 필요 없다(실측: 쿠키 없이도 200)
|
|
241
|
+
*
|
|
242
|
+
* @param name 의원명 (목록의 발의자 표기와 같은 한글 이름)
|
|
243
|
+
* @param ageFrom 대수 시작 (기본값 `01`)
|
|
244
|
+
* @param ageTo 대수 끝 (기본값 `99`)
|
|
245
|
+
*/
|
|
246
|
+
findRepresentCandidates(name: string, ageFrom?: string | number, ageTo?: string | number): Promise<ILikmsRepresentCandidate[]>;
|
|
247
|
+
/**
|
|
248
|
+
* 대수 범위의 **소관위원회 목록**을 조회합니다 (`/bi/bill/sch/findAgeCmt.do`).
|
|
249
|
+
*
|
|
250
|
+
* 검색 파라미터 `ageCmtId`는 이름이 아니라 코드를 받으므로, 이름밖에 모를 때
|
|
251
|
+
* 이 메서드로 코드를 확인한다. 위원회 구성은 대수마다 달라지므로 범위를 좁혀
|
|
252
|
+
* 조회한다(실측: `ageFrom=22&ageTo=22` → 22대 25건). 범위를 주지 않으면 전체
|
|
253
|
+
* 대수를 합친 목록을 주며, 이때는 같은 이름이 코드별로 나뉘어
|
|
254
|
+
* `보건복지위원회(18대~22대)`처럼 대수 꼬리표가 붙는다.
|
|
255
|
+
*
|
|
256
|
+
* - `ageFrom`/`ageTo`는 **둘 다** 줘야 범위가 적용된다(한 쪽만 주면 서버가 무시하므로 예외).
|
|
257
|
+
* - 브라우저와 같은 GET이며 CSRF 토큰·세션이 필요 없다(실측: 쿠키 없이 200).
|
|
258
|
+
* - 응답이 JSON이 아니면 빈 배열(예외 없음), 네트워크 오류는 전파한다.
|
|
259
|
+
*/
|
|
260
|
+
findCommittees(ageFrom?: string | number, ageTo?: string | number): Promise<ILikmsCommittee[]>;
|
|
261
|
+
/**
|
|
262
|
+
* 계류의안 목록 조각 HTML을 AJAX(POST)로 반환합니다.
|
|
263
|
+
*
|
|
264
|
+
* 브라우저와 동일하게 세션 페이지의 숨김 폼 필드를 본문 기본값으로 보내고,
|
|
265
|
+
* CSRF 토큰을 `X-CSRF-TOKEN` 헤더로 전송합니다. 토큰이 만료된 경우
|
|
266
|
+
* 세션을 다시 발급받아 1회 재시도합니다.
|
|
267
|
+
*/
|
|
268
|
+
getStateListHTML(query?: ILikmsStateQuery): Promise<string>;
|
|
269
|
+
/** HttpClient가 세션/CSRF 거부(401·403)로 실패했는지 판별합니다. */
|
|
270
|
+
private isSessionRejection;
|
|
271
|
+
/** 목록 조각 HTML에서 계류의안 검색 결과를 파싱하여 반환합니다. */
|
|
272
|
+
parseList(html: string): ILikmsStateSearchResult;
|
|
273
|
+
/**
|
|
274
|
+
* `hasProposalReason`인 법안의 제안이유를 의안상세에서 조회해 `proposalReason`에 채웁니다.
|
|
275
|
+
*
|
|
276
|
+
* 목록 HTML에는 제안이유 본문이 없어 건마다 2회(상세 페이지 + `billInfo.do`) 요청이 든다.
|
|
277
|
+
* `hasProposalReason`가 false인 건은 조회하지 않고, 조회·파싱에 실패한 건은 기존 값
|
|
278
|
+
* (`null`)을 유지하며 예외를 던지지 않는다.
|
|
279
|
+
*
|
|
280
|
+
* @param items 보정할 목록 (입력 배열은 변경하지 않는다)
|
|
281
|
+
* @param options `delayMs`(기본 500)·`concurrency`(기본 1)로 요청 속도를 조절한다.
|
|
282
|
+
* @returns 보정된 복사본 배열
|
|
283
|
+
*/
|
|
284
|
+
hydrateProposalReasons(items: ILikmsStateBillItem[], options?: IBulkOptions): Promise<ILikmsStateBillItem[]>;
|
|
285
|
+
/**
|
|
286
|
+
* 계류의안을 검색합니다. 필터를 지정하지 않으면 1페이지를 반환합니다.
|
|
287
|
+
* `hydrateProposalReason`이 켜져 있으면 `hasProposalReason` 건의 제안이유도 채웁니다.
|
|
288
|
+
*/
|
|
289
|
+
search(query?: ILikmsStateQuery): Promise<ILikmsStateSearchResult>;
|
|
290
|
+
/** 특정 페이지의 계류의안 목록을 반환합니다. */
|
|
291
|
+
getPage(pageIndex: number, query?: Omit<ILikmsStateQuery, 'pageIndex'>): Promise<ILikmsStateBillItem[]>;
|
|
292
|
+
private _getAllPagesImpl;
|
|
293
|
+
/**
|
|
294
|
+
* 계류의안 전체 페이지를 순차적으로 yield하는 async generator.
|
|
295
|
+
* `IBulkOptions`로 딜레이·동시성·최대 페이지를 조절할 수 있습니다.
|
|
296
|
+
*/
|
|
297
|
+
getAllPages(query?: Omit<ILikmsStateQuery, 'pageIndex'>, options?: IBulkOptions): AsyncGenerator<ILikmsStateSearchResult>;
|
|
298
|
+
/**
|
|
299
|
+
* 심사진행단계가 '접수'(위원회 회부 이전)인 항목만 남깁니다.
|
|
300
|
+
*
|
|
301
|
+
* 국민참여입법센터 `searchPending`(`rslRsltNmL=900101` '발의')에 대응하는 판정이다.
|
|
302
|
+
* 실측(2026-10-13)에서 likms 계류의안의 '접수' 항목과 NSM '발의' 결과가 같은
|
|
303
|
+
* 부분집합임을 확인했다(표본 13건 중 12건 일치).
|
|
304
|
+
*/
|
|
305
|
+
filterPending(items: ILikmsStateBillItem[]): ILikmsStateBillItem[];
|
|
306
|
+
/**
|
|
307
|
+
* 접수(위원회 회부 이전) 법안을 페이지 단위로 순차적으로 yield합니다.
|
|
308
|
+
*
|
|
309
|
+
* likms 서버에는 심사진행상태를 좁히는 **유효한** 필터가 없다(파라미터 `srngPrgrsSttsCd`는
|
|
310
|
+
* 존재하지만 값을 알 수 없다 — `agent_memories/findings` 참조). 그래서 목록을 앞에서부터
|
|
311
|
+
* 스캔하며 클라이언트에서 걸러낸다. 따라서:
|
|
312
|
+
* - 접수 항목이 없는 페이지는 건너뛰므로 `currentPage`는 원본 페이지 번호가 아니다.
|
|
313
|
+
* - `items`는 접수 항목만이고, `total`/`totalPages`는 전체(접수 포함) 기준 원본 값이다.
|
|
314
|
+
*
|
|
315
|
+
* 스캔 기본 페이지 크기는 100건(사이트 지원 값)이라 `pageSize`를 주지 않으면 요청 수가 준다.
|
|
316
|
+
* 스캔 범위는 `options.maxPages`로 제한한다.
|
|
317
|
+
*/
|
|
318
|
+
getAllPendingPages(query?: Omit<ILikmsStateQuery, 'pageIndex'>, options?: IBulkOptions): AsyncGenerator<ILikmsStateSearchResult>;
|
|
319
|
+
/**
|
|
320
|
+
* 접수(위원회 회부 이전) 법안이 있는 첫 페이지를 반환합니다.
|
|
321
|
+
*
|
|
322
|
+
* 서버 필터가 없어 앞에서부터 스캔하며, `options.maxPages`(기본 10) 안에서 찾지 못하면
|
|
323
|
+
* 빈 결과(`items: []`)를 반환한다. `searchPending`을 페이지 단위로 순회하려면
|
|
324
|
+
* `getAllPendingPages`를 쓴다(페이지 번호가 원본과 다르므로 `pageIndex`로 건너뛸 수 없다).
|
|
325
|
+
*/
|
|
326
|
+
searchPending(query?: Omit<ILikmsStateQuery, 'pageIndex'>, options?: IBulkOptions): Promise<ILikmsStateSearchResult>;
|
|
327
|
+
}
|