-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10 from code-yeongyu/naver-parser
`NaverPay` 의 구매기록을 조회 할 경우 `pupeteer` 대신 `axios` 를 활용해 `http request` 를 보내어 parsing 하도록 변경합니다.
- Loading branch information
Showing
20 changed files
with
682 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
import Module from "./module"; | ||
import PaymentHistory from "./paymentHistory"; | ||
import PaymentHistory from "./types/paymentHistory"; | ||
|
||
export { Module, PaymentHistory }; |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export interface CommonResponse { | ||
readonly status: number; | ||
readonly data: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,16 @@ | ||
import { URLChanger, PageInteractor, ElementParser } from "."; | ||
import { | ||
URLChanger, | ||
PageInteractor, | ||
ElementParser, | ||
NaverScraper, | ||
NaverParser, | ||
} from "."; | ||
import { Module as BaseModule } from "../common"; | ||
|
||
export default interface Module extends BaseModule { | ||
readonly urlChanger: URLChanger; | ||
readonly pageInteractor: PageInteractor; | ||
readonly elementParser: ElementParser; | ||
readonly scraper: NaverScraper; | ||
readonly parser: NaverParser; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,27 @@ | ||
import puppeteer from "puppeteer"; | ||
import { Module, URLChanger, ElementParser, PageInteractor } from "."; | ||
import { | ||
Module, | ||
URLChanger, | ||
ElementParser, | ||
PageInteractor, | ||
NaverScraper, | ||
NaverParser, | ||
} from "."; | ||
|
||
export default class ModuleFactory { | ||
static create(page: puppeteer.Page): Module { | ||
const urlChanger = new URLChanger(page); | ||
const elementParser = new ElementParser(page); | ||
const pageInteractor = new PageInteractor(page, elementParser); | ||
const scraper = new NaverScraper(); | ||
const parser = new NaverParser(); | ||
|
||
return { | ||
urlChanger, | ||
pageInteractor, | ||
elementParser, | ||
scraper, | ||
parser, | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { NaverParser } from "./parser"; | ||
import { | ||
expectedPaymentHistoryItems, | ||
searchPaymentHistoryJson, | ||
} from "./testFixture"; | ||
|
||
describe("NaverParser", () => { | ||
describe("parsePaymentHistory", () => { | ||
it("should parse", () => { | ||
// given | ||
const parser = new NaverParser(); | ||
|
||
// when | ||
const result = parser.parsePaymentHistory(searchPaymentHistoryJson); | ||
|
||
// then | ||
expect(result).toEqual(expectedPaymentHistoryItems); | ||
}); | ||
}); | ||
|
||
describe("parseInformationForNextPaymentHistory", () => { | ||
it("should parse", () => { | ||
// given | ||
const parser = new NaverParser(); | ||
|
||
// when | ||
const result = parser.parseInformationForNextPaymentHistory( | ||
searchPaymentHistoryJson | ||
); | ||
|
||
// then | ||
expect(result.hasNext).toBe(true); | ||
expect(result.lastHistoryId).toBe("order-2021110243152861"); | ||
expect(result.lastHistoryDateTimestamp).toBe(1635853254000); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { PaymentHistory } from "app/common"; | ||
import { PaymentHistoryResponse } from "./types/paymentHistoryResponse"; | ||
|
||
export class NaverParser { | ||
parsePaymentHistory(jsonString: string): PaymentHistory[] { | ||
const data = JSON.parse(jsonString) as PaymentHistoryResponse; | ||
const items = data.result.items; | ||
const paymentHistories = items.map((item): PaymentHistory => { | ||
const name = item.product.name; | ||
const price = item.product.price; | ||
const thumbnailURL = item.product.imgUrl; | ||
const paymentStatus = item.status.text; | ||
const isAdditional = !!item.additionalData.isSupplemented; | ||
const purchasedAtTimestamp = item.date; | ||
const purchasedAt = new Date(purchasedAtTimestamp); | ||
return { | ||
name, | ||
price, | ||
thumbnailURL, | ||
paymentStatus, | ||
isAdditional, | ||
purchasedAt, | ||
}; | ||
}); | ||
return paymentHistories; | ||
} | ||
|
||
parseInformationForNextPaymentHistory(jsonString: string): { | ||
hasNext: boolean; | ||
lastHistoryId: string; | ||
lastHistoryDateTimestamp: number; | ||
} { | ||
const data = JSON.parse(jsonString) as PaymentHistoryResponse; | ||
|
||
const hasNext = data.result.hasNext; | ||
const lastHistoryId = data.result.lastId; | ||
const lastHistoryDateTimestamp = data.result.lastDate; | ||
return { hasNext, lastHistoryId, lastHistoryDateTimestamp }; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import axios from "axios"; | ||
import { NaverScraper } from "./scraper"; | ||
describe("Scraper", () => { | ||
describe("searchPaymentHistory", () => { | ||
it("should create an post request", async () => { | ||
// given | ||
const cookies = ""; | ||
const scraper = new NaverScraper(); | ||
const postSpy = jest.spyOn(axios, "post"); | ||
postSpy.mockImplementation(() => Promise.resolve({ data: {} })); | ||
|
||
// when | ||
await scraper.searchPaymentHistory(cookies); | ||
|
||
// then | ||
expect(postSpy).toBeCalledWith( | ||
scraper.searchPaymentHistoryURL, | ||
expect.any(Object), | ||
expect.objectContaining({ | ||
headers: expect.objectContaining({ | ||
Cookie: cookies, | ||
}), | ||
}) | ||
); | ||
}); | ||
}); | ||
|
||
describe("nextPaymentHistory", () => { | ||
it("should create an post request", async () => { | ||
// given | ||
const second = 1000; | ||
const minute = second * 60; | ||
const hour = minute * 60; | ||
const day = hour * 24; | ||
|
||
const cookies = ""; | ||
const scraper = new NaverScraper(); | ||
const postSpy = jest.spyOn(axios, "post"); | ||
postSpy.mockImplementation(() => Promise.resolve({ data: {} })); | ||
|
||
// when | ||
await scraper.nextPaymentHistory( | ||
cookies, | ||
"order-1234", | ||
new Date().getTime() - day * 30 | ||
); | ||
|
||
// then | ||
expect(postSpy).toBeCalledWith( | ||
scraper.nextPaymentHistoryURL, | ||
expect.any(Object), | ||
expect.objectContaining({ | ||
headers: expect.objectContaining({ | ||
Cookie: cookies, | ||
}), | ||
}) | ||
); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { CommonResponse } from "app/common/types/response"; | ||
import axios from "axios"; | ||
import { ServiceGroup } from "./types/serviceGroup"; | ||
import { StatusGroup } from "./types/statusGroup"; | ||
|
||
export class NaverScraper { | ||
private async getTodayString() { | ||
const today = new Date(); | ||
const year = today.getFullYear(); | ||
const month = today.getMonth() + 1; | ||
const date = today.getDate(); | ||
const monthString = month >= 10 ? month : "0" + month; | ||
const dateString = date >= 10 ? date : "0" + date; | ||
return `${year}-${monthString}-${dateString}`; | ||
} | ||
|
||
searchPaymentHistoryURL = | ||
"https://new-m.pay.naver.com/api/timeline/searchPaymentHistory"; | ||
async searchPaymentHistory( | ||
cookies: string, | ||
searchOptions?: { | ||
keyword: string; | ||
serviceGroup: ServiceGroup; | ||
statusGroup: StatusGroup; | ||
} | ||
): Promise<CommonResponse> { | ||
const data = { | ||
keyword: searchOptions?.keyword || null, | ||
startDate: "2000-01-01", | ||
endDate: await this.getTodayString(), | ||
serviceGroup: searchOptions?.serviceGroup || null, | ||
statusGroup: searchOptions?.statusGroup || null, | ||
}; | ||
const options = { | ||
headers: { | ||
Cookie: cookies, | ||
"content-type": "application/json;charset=UTF-8", | ||
}, | ||
}; | ||
const response = await axios.post( | ||
this.searchPaymentHistoryURL, | ||
data, | ||
options | ||
); | ||
|
||
return { status: response.status, data: JSON.stringify(response.data) }; | ||
} | ||
|
||
nextPaymentHistoryURL = | ||
"https://new-m.pay.naver.com/api/timeline/nextPaymentHistory"; | ||
async nextPaymentHistory( | ||
cookies: string, | ||
lastHistoryId: string, | ||
lastHistoryDateTimestamp: number, | ||
searchOptions?: { | ||
keyword: string; | ||
serviceGroup: ServiceGroup; | ||
statusGroup: StatusGroup; | ||
} | ||
): Promise<CommonResponse> { | ||
const data = { | ||
keyword: searchOptions?.keyword || null, | ||
startDate: "2000-01-01", | ||
endDate: await this.getTodayString(), | ||
serviceGroup: searchOptions?.serviceGroup || null, | ||
statusGroup: searchOptions?.statusGroup || null, | ||
lastId: lastHistoryId, | ||
lastDate: lastHistoryDateTimestamp, | ||
}; | ||
const options = { | ||
headers: { | ||
Cookie: cookies, | ||
"content-type": "application/json;charset=UTF-8", | ||
}, | ||
}; | ||
const response = await axios.post( | ||
this.nextPaymentHistoryURL, | ||
data, | ||
options | ||
); | ||
return { status: response.status, data: JSON.stringify(response.data) }; | ||
} | ||
} |
Oops, something went wrong.