일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- vavr
- 아이온큐
- file download
- request cache
- mysql
- TSLA
- redis
- Query
- elasticsearch cache
- JPA
- Aggregation
- 테슬라
- Elasticsearch
- Docker
- aqqle
- java crawler
- api cache
- IONQ
- dbeaver
- java
- KNN
- Elastic
- 양자컴퓨터
- Analyzer
- NORI
- ann
- API
- Selenium
- aggs
- Cache
Archives
- Today
- Total
아빠는 개발자
[Aqqle] Ya후 finance 긁어보자 2 본문
728x90
반응형
몇일 전까지 다운로드 링크를 제공했었는데.. 막혔다.
치사하다..
그래서 또 긁어야 겠다.
주가정보를 훔쳐서 보관할 테이블 생성
CREATE TABLE `stock_data` (
`id` bigint NOT NULL AUTO_INCREMENT,
`company` varchar(100) NOT NULL,
`company_code` varchar(20) NOT NULL,
`trading_date` date NOT NULL,
`open` float DEFAULT NULL,
`high` float DEFAULT NULL,
`low` float DEFAULT NULL,
`close` float DEFAULT NULL,
`adj_close` float DEFAULT NULL,
`volume` bigint DEFAULT NULL,
`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`company_code`,`trading_date`),
UNIQUE KEY `unique_id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
재물로 사용할 페이지 주가정보의 히스토리를 가지고 있는..
원랜 다운로드를 제공해서 편하게 사용했는데 프리미엄 구독을 해야 다운로드를 제공하는걸로 바뀐듯..
date 를 사용할때는 Unix Epoch 로 계산해서 사용해야 한다.
Unix Epoch이란?
- Unix Epoch: 1970년 1월 1일 00:00:00 UTC를 기준으로 합니다. 이 시점은 Unix 시스템의 시작 시점으로, 시간 계산의 기준점 역할을 합니다.
일단 자바로 긁었다.
거래일이 Sep 13, 2024 이런식이라 포맷을 맞춰주는 부분을 .. 귀찮아서 그냥 넣음.. 나중에 정리해야지..
일단 되게 만 해놓고
package com.doo.aqqle.service;
import com.doo.aqqle.element.Site;
import com.doo.aqqle.factory.SiteFactory;
import com.doo.aqqle.factory.YahooDataFactory;
import com.doo.aqqle.repository.Stock;
import com.doo.aqqle.repository.StockData;
import com.doo.aqqle.repository.StockDataRepository;
import com.doo.aqqle.repository.StockRepository;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@Service("YahooDataService")
public class YahooDataService extends AqqleService implements AqqleCrawler {
public YahooDataService(
StockRepository stockRepository,
StockDataRepository stockDataRepository) {
super(stockRepository, stockDataRepository);
}
private final int CRAWLING_COUNT = 25;
@Override
public void execute() {
List<Stock> stockList = stockRepository.findAllByUseYn("Y");
Site site = SiteFactory.getSite(new YahooDataFactory());
stockList.stream().forEach(x -> {
LocalDate localDate = LocalDate.parse(x.getStartDate());
long period1 = localDate.atStartOfDay(ZoneId.of("UTC")).toEpochSecond();
long period2 = Instant.now().getEpochSecond();
Map<String, Long> periodMap = new HashMap<>();
periodMap.put("period1", period1);
periodMap.put("period2", period2);
site.getUrl(x.getCompanyCode(), periodMap);
String listUrl = site.getUrl(x.getCompanyCode(), periodMap);
System.out.println(listUrl);
try {
Document listDocument = Jsoup.connect(listUrl)
.timeout(5000)
.get();
Elements tableTr = listDocument.select(site.getListCssSelector());
tableTr.stream()
.map(tr -> tr.select("td").stream()
.map(Element::text) // 각 td 요소의 텍스트를 추출
.collect(Collectors.toList()) // 추출한 텍스트를 리스트로 수집
)
.filter(tds -> tds.size() > 6)
.forEach(tdTexts -> {
StockData stockData = new StockData();
DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("MMM d, yyyy", Locale.ENGLISH);
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate date = LocalDate.parse(tdTexts.get(0), inputFormatter);
// 날짜를 원하는 형식으로 포맷
String tradingDate = date.format(outputFormatter);
stockData.setCompany(x.getCompany());
stockData.setCompanyCode(x.getCompanyCode());
stockData.setTradingDate(tradingDate); // 첫 번째 항목: 거래일
stockData.setOpen(Float.parseFloat(tdTexts.get(1).replace(",", ""))); // 두 번째 항목: 시가
stockData.setHigh(Float.parseFloat(tdTexts.get(2).replace(",", ""))); // 세 번째 항목: 최고가
stockData.setLow(Float.parseFloat(tdTexts.get(3).replace(",", ""))); // 네 번째 항목: 최저가
stockData.setClose(Float.parseFloat(tdTexts.get(4).replace(",", ""))); // 다섯 번째 항목: 종가
stockData.setAdjClose(Float.parseFloat(tdTexts.get(5).replace(",", ""))); // 여섯 번째 항목: 수정 종가
Long volume = 0L;
if(!tdTexts.get(6).replace(",", "").replace("-", "").isBlank()) {
volume = Long.parseLong(tdTexts.get(6).replace(",", "").replace("-", ""));
}
stockData.setVolume(volume); // 일곱 번째 항목: 거래량
stockDataRepository.upsert(
stockData.getCompany(),
stockData.getCompanyCode(),
stockData.getTradingDate(),
stockData.getOpen(),
stockData.getHigh(),
stockData.getLow(),
stockData.getClose(),
stockData.getAdjClose(),
stockData.getVolume()
);
});
} catch (IOException e) {
e.printStackTrace();
}
log.info("DATA 저장 완료.");
});
}
}
repository 를 upsert 로 만들
public interface StockDataRepository extends JpaRepository<StockData, Long> {
@Modifying
@Transactional
@Query(value = "INSERT INTO stock_data (company, company_code, trading_date, open, high, low, close, adj_close, volume) " +
"VALUES (:company, :companyCode, :tradingDate, :open, :high, :low, :close, :adjClose, :volume) " +
"ON DUPLICATE KEY UPDATE company = VALUES(company), open = VALUES(open), high = VALUES(high), " +
"low = VALUES(low), close = VALUES(close), adj_close = VALUES(adj_close), volume = VALUES(volume), " +
"updated_time = CURRENT_TIMESTAMP", nativeQuery = true)
void upsert(String company, String companyCode, String tradingDate, Float open, Float high,
Float low, Float close, Float adjClose, Long volume);
}
훔친물건
이제 깨끗하게 세탁해서 뒷탈없게 사용해야겠다.
728x90
반응형
'Aqqle > CRAWLER' 카테고리의 다른 글
[Aqqle] 상품데이터 긁어보자 (2) | 2024.10.08 |
---|---|
[Aqqle] 야hoo finance 긁어보자 (4) | 2024.09.01 |