instagram scrape query 또 다시 수정

최봉수·2023년 12월 6일
0

기존에 계속 개발하며 테스트하던 ?__a=1&__d=dis 쿼리가 에러가 자주 발생한다.
스택오버플로우를 뒤져보니 해당 쿼리가 막혔다, 패치됐다, 로그인 세션이 필요하다, 쿠키에서 특정 값을 지워서 보내야한다 등등 여러 의견이 분분해 정확한 원인 파악이 힘들었다.

왜냐하면 로그인하면 당연히 잘 나온다 세션이 있기에.
근데 어쩔때는 비 로그인 상태에서도 잘 출력이 됐다가 갑자기 또 안됐다가 그런다.
정말 의심가는 여러 케이스를 다 테스트 해봤던 거 같다.

너무 안정성이 떨어진다.
물론 Puppeteer를 이용해서 인스타그램 접속 후 로그인 한 다음에 query url로 접속해서 정보를 가져오면 되긴한다.
하지만, 그렇게되면 내가 아닌 누군가의 인스타그램 계정이 항상 필요해진다. 그렇게되면 초기에 만들고자 하는 목표와 다르다.

그리고 새로운 방법을 찾았다!

스택오버플로우는 신이다.

무념무상 검색을 하던 도중 비교적 최근 질문에서 발견했다.
질문에 보면 로그인이나 쿠키 없이 작동한다고 무심한 답변이 하나 있다.

https://www.instagram.com/graphql/query/?query_hash=b3055c01b4b222b8a47dc12b090e4e64&variables={"shortcode":"CtO-WItvI4d"}

그 동안 구글링 하던 도중 query_hash를 이용한 답변이 몇개 있었었고 이번에도 로그인이나 쿠키 없이 작동한다는 최신 답변이었기에 instagram query_hash에 대해서 폭풍 구글링을 시작했다.

그 결과 query_hash마다 릴스, 동영상, 해쉬태그, 프로필 등 가져올 수 있을 종류가 존재했고 같이 넘기는 변수도 존재했다.

그래서 나에게 필요한 query_hash를 찾기아보려 했지만, 인스타그램 내부 로직이나 변경사항에 따라 언제든지 바뀔 수 있고 알 수 있는 방법은 제한적이며 일반적인 사용자가 이를 얻는 것은 어렵다고 그런다.

그래도 방법을 소개한 포스팅을 찾아서 한번 시도를 해봤다.

그 결과 몇년전 글이라 인스타그램 내부의 로직이 변했는지 중간부터 따라갈 수가 없었다.
그래서 무식하게 b3055c01b4b222b8a47dc12b090e4e64 hash 값 자체를 구글에 때려 박았더니
엥? 관련 결과가 꽤나 나온다.

거기서 해당 포스팅을 찾았고 이 포스팅으로 해결했다.

그러면서 hash값으로 여러번 검색해본 결과 몇년 전 솔루션 답변임에도 아직까지 그대로 작동을 하고 있었으며, 어디서 봤는지 기억이 안나지만 이 query_hash는 fix된 값이라 변하지 않는다는 정보를 보았다.

아무리 생각해봐도 이전에 쓰고있던 ?__a=1&__d=dis 쿼리보다는 훨씬 안전해보인다.
바로 바꾸자!

간단한 코드 수정

서버

// 피드 데이터 가져오기
app.get('/getFeedData', async (req, res) => {
	try {
		const { ig_owner_id } = req.headers;
		const scrapeData = await getScrapeData(`https://www.instagram.com/graphql/query/?query_hash=e769aa130647d2354c40ea6a439bfc08&variables={"id":"${ig_owner_id}", "first":12 }`);

		if (scrapeData.status !== 'ok') {
			throw new Error(scrapeData.message);
		}

		res.json(scrapeData);
	} catch (error) {
		handleServerError(res, error, '피드 데이터를 가져오는 중 오류가 발생했습니다.');
	}
});

클라이언트

const IG_INFO = [
	{ ig_name: 'wyfood_nutri', ig_owner_id: '51911981179', filter: wyFoodFilter },
	{ ig_name: 'onnuri_r', ig_owner_id: '54694139311', filter: onnuriFilter },
	{ ig_name: 'babplus_f1', ig_owner_id: '49021404102', filter: babPlusFilter },
];


async function init() {
	// 마지막 업데이트 날짜 체크
	const lastUpdates = Object.values(lunchData).map((value) => value.lastUpdate);
	const isNotLatest = lastUpdates.some((value) => value !== getCurrentDate());

	try {
		// 최신이 아닐 경우 실행
		if (isNotLatest && isUpdateTime()) {
			for (const { ig_name, ig_owner_id, filter } of IG_INFO) {
				// 서버에서 json 파일 수정 때문에 all로 처리하면 데이터 엉킴
				await updateMenu(ig_name, ig_owner_id, filter);
			}
			updateMenuImages();
		} else {
			renderMenuImages(lunchData);
		}
	} catch (error) {
		handleClientError(error, 'init Function');
	}
}

// 및 필터링 함수 로직 변경 등

url과 가지고오는 데이터 구조의 차이가 있을 뿐이라 크게 바뀐 점은 없다.
무지성 새로고침에도 문제 없다.
너무 좋당

또 다른 방법

이 방법 역시 시간이 지나서 막히면 어쩌지? 그래도 최신 정보를 가지고 있는게 더 좋지 않을까? 라는 생각이 들었다.

그래서 처음에 봤던 query_hash 찾는 방법을 베이스로 검색을 해가며 똑같은 데이터를 가져오는 전혀 다른 url을 찾아왔다.

구글링하며 하나하나 링크를 기록할 순 없기에...
링크 첨부는 못하지만 내가 기록용으로 남겨둔 주석이라도 있으니 해당 주석으로 대체해야겠다.

/**
 * 유저 데이터 가져오는 쿼리 url 찾는 방법
 * query_hash와 해당 방법에서 가져오는 doc_id의 차이점은 doc_id는 GraphQL 쿼리 문서의 고유한 ID이고, 특정 쿼리 문서를 가리킨다. 그리고 GraphQL 쿼리 자체가 아니라 해당 쿼리의 ID에 의존한다고 한다.
 * 이러한 차이점과 doc_id는 비교적 최근에 생긴(혹은 바뀐) 쿼리 같아서 안정성이 불확실하고, 현재로써는 query_hash가 몇년전 답변임에도 지금까지 값이 변경되지않고 사용가능한 것을 보면 더 안정적으로 생각되기에 참고용으로만 기록
 *
 * 1. 인스타그램 프로필에 접속 https://www.instagram.com/{user}/
 * 2. 개발자 도구 > Network > XHR 필터 적용
 * 3. 게시물을 스크롤해서 새 게시물이 로드되면 ?doc_id='...로 시작하는 새로운 XHR 요청이 보임
 * 4. 해당 요청의 Request URL Decode
 * 5. variables값 중에 첫 12개만 필요하기에 end_cursor 값인 after는 필요 없으니 제거
 *
 * EX) https://www.instagram.com/graphql/query/?doc_id=17991233890457762&variables={"id":"{프로필 고유 id}","first":12}
 */

이제 정말 문제 없겠지...?

이번주내로 나스에 서버를 띄워서 테스트 해봐야겠다!

profile
돈이 좋아

0개의 댓글