프론트단(클라이언트단에서 해외 사이트 서버 크롤링시 CORS 오류)
<div id="imageContainer" class="sp_vbox img_fix2"></div>
// iframe 방식
let detailUrl = data.result.globalData.detailModel.detailUrl;
let imageContainer = document.getElementById('imageContainer');
imageContainer.innerHTML = `<iframe src="${detailUrl}" style="width: 100%; height: 100%;">${detailUrl}</iframe>`;
"detailUrl": "https://[해외에서 크롤링 해오는 url]"
detailUrl에 있는 html페이지의 이미지들을 보여주는 코드 작성 (CORS 오류 발생)
// detailUrl내 img 가져오기
let detailUrl = data.result.globalData.detailModel.detailUrl;
fetch(detailUrl)
.then(response => response.text())
.then(html => {
let parser = new DOMParser();
let doc = parser.parseFromString(html, 'text/html');
let imageTags = doc.getElementById('img');
let imageContainer = document.getElementById('imageContainer');
imageContainer.innerText = '';
for(let i = 0; i < imageTags.length; i++) {
imageContainer.appendChild(imageTags[i]);
}
})
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
let detailUrl = data.result.globalData.detailModel.detailUrl;
fetch(detailUrl)
.then(response => response.text())
.then(html => {
let parser = new DOMParser();
let doc = parser.parseFromString(html, 'text/html');
document.body.appendChild(doc.body);
html2canvas(doc.body).then(canvas => {
document.body.appendChild(canvas);
});
});
<script src="https://cdn.jsdelivr.net/npm/node-http-server@8.1.5/server/Server.min.js"></script>
async function fetchHTML(url) {
try {
let response = await fetch(url);
let data = await response.text();
return data;
} catch (err) {
console.error(err);
}
}
function fetchItemDetail(itemId) {
fetch(`http://192.168.0.158:8000/getItemDetail?id=${itemId}`)
.then(response => response.json())
.then(data => {
let detailUrl = data.result.globalData.detailModel.detailUrl;
return fetchHTML(detailUrl);
})
.then(html => {
let parser = new DOMParser();
let doc = parser.parseFromString(html, 'text/html');
let imageTags = doc.getElementsByTagName('img');
let imageContainer = document.getElementById('imageContainer');
for(let i = 0; i < imageTags.length; i++) {
imageContainer.appendChild(imageTags[i]);
}
})
.catch(error => console.error('Error:', error));
}
<script>
// JSONP callback function
function handleResponse(response) {
console.log(response);
// 이미지 URL을 추출하는 코드 추가 필요
}
// JSONP request
const script = document.createElement('script');
script.src = `https://[url]/api?callback=handleResponse`;
document.body.appendChild(script);
</script>
해결된 방법
html 내에 puppeteer.js를 사용해 크롬이나 크로미움 웹 브라우저를 띄워 해외 사이트를 보여주고 있다.
그러다 보니 해외 사이트도 느리고 불러오는 데이터도 많은데 그 안에 html을 또 띄우는 작업을 하다보니 fetch 데이터 불러오기 오류가 자꾸 발생하고 있다.
온로드시 주어진 url을 프록시 서버에 post 요청을 보내 html 콘텐츠를 가져와 DOMParser를 사용해 html 문서로 변환한다.
이렇게 하면 그 안에 내용의 css도 수정 가능하다.
window.onload = function () {
async function fetchHTML(url) {
try {
console.log("fetchHTML");
console.log(url);
const proxy = "[프록시 url]";
const data = {"url": url};
const response = await fetch(proxy, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams(data).toString()
});
const htmlContent = await response.text();
console.log("ajax_detail");
console.log(htmlContent);
const parser = new DOMParser();
const doc = parser.parseFromString(htmlContent, 'text/html');
// ID 'detail-root'의 요소
const element = doc.getElementById('detail-root');
const container = document.getElementById("imageContainer");
// 단일 요소를 처리
if (element) {
// #detail-root 하위 모든 div에 너비 100%
const divElements = element.querySelectorAll('div');
for (let i = 0; i < divElements.length; i++) {
divElements[i].style.width = '100%';
}
// 요소를 복제하여 삽입
container.appendChild(element.cloneNode(true));
} else {
console.log('#detail-root 요소를 찾을 수 없습니다.');
}
} catch (error) {
console.error('Error:', error);
}
}
function fetchItemDetail(itemId) {
let data = { url: itemId };
fetch('http://[url]', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(response => {
console.log(response)
if (!response.ok) {
throw new Error('네트워크 응답 오류');
}
return response.json();
})
.then(data => {
let detailUrl = data.result.globalData.detailModel.detailUrl;
return fetchHTML(detailUrl);
})
.catch(error => console.error('Error:', error));
}
}
느낀 점
백엔드에서도 해당 페이지 크롤링시 html내에 코드를 긁어오니 js라이브러리를 사용해 불러오는 것으로 이미지 태그나 html내의 코드의 내용들을 가져올 수 없는 현상들이 일어났는데 Puppeteer.js를 사용해 cors 정책을 우회해 데이터를 가져올 수 있다니 신세계였다. 근데 로그가 찍히고 자꾸 요청하다보니 막히는 현상이 일어나는 것 같았다. 작업하고 있는 우리 쪽 ip도 계속 찍힐 거고...