YouTube 구독을 CSV 형식으로 다운로드(Google 테이크아웃이 너무 오래 걸리기 때문에)

내 YouTube 구독을 open-source Android YouTube client NewPipe로 가져오고 싶었습니다. 이를 수행하는 일반적인 방법은 계정에 대한 데이터를 검색할 수 있도록 Google에서 제공하는 서비스인 Google 테이크아웃에서 구독을 내보내는 것입니다. NewPipe는 프로세스를 친절하게 설명합니다.


제가 가장 좋아하는 글꼴입니다.

NewPipe의 지침은 다음과 같습니다.

Import YouTube subscriptions from Google takeout:

  1. Go to this URL:
  2. Log in when asked
  3. Click on "All data included", then on "Deselect all", then select only "subscriptions" and click "OK"
  4. Click on "Next step" and then on "Create export"
  5. Click on the "Download" button after it appears
  6. Click on IMPORT FILE below and select the downloaded .zip file
  7. [If the .zip import fails] Extract the .csv file (usually under "YouTube and YouTube Music/subscriptions/subscriptions.csv"), click on IMPORT FILE below and select the extracted csv file


그들이 언급하지 않은 것은 Google 테이크아웃을 완료하는 데 많은 시간이 걸릴 수 있다는 것입니다.

Google 테이크아웃을 사용해 보았지만 한 시간을 기다린 후 다른 것을 시도해 보기로 했습니다. 구독하고 있는 채널 목록을 스크랩하고 해당 목록을 NewPipe로 가져올 수 있는 CSV 파일로 저장합니다.

Google 테이크아웃 CSV의 형식 지정 방법 알아보기



NewPipe가 마치 Google 테이크아웃 CSV인 것처럼 받아들이는 나만의 파일을 만들기 위해 Google 테이크아웃이 사용하는 형식을 찾아야 했습니다.

https://github.com/TeamNewPipe/NewPipeExtractor/pull/709/commits/94a29fd63ff6bb0c1805c44ef5ebf4d915427454

Google 테이크아웃 가져오기 지원을 추가한 커밋을 찾았습니다. 그 커밋 안에는 파일에 대한 설명이 있었습니다.

// Expected format of CSV file:
//      Channel Id,Channel Url,Channel Title
//      UC1JTQBa5QxZCpXrFSkMxmPw,http://www.youtube.com/channel/UC1JTQBa5QxZCpXrFSkMxmPw,Raycevick
//      UCFl7yKfcRcFmIUbKeCA-SJQ,http://www.youtube.com/channel/UCFl7yKfcRcFmIUbKeCA-SJQ,Joji
//
// Notes:
//      It's always 3 columns
//      The first line is always a header
//      Header names are different based on the locale
//      Fortunately the data is always the same order no matter what locale


이것은 충분히 간단했습니다. 이제 내가 구독하는 각 채널의 채널 ID 및 채널 제목 ​​목록을 얻는 방법을 찾아야 했습니다.

유튜브 스크래핑



YouTube에서 페이지를 찾았습니다. 나는 이 페이지가 어떻게 작동하는지 살펴보았고 페이지가 ytInitialData라는 변수 안에 데이터를 저장한다는 것을 깨달았습니다. 이 변수는 구독 중인 채널 목록과 기타 데이터를 저장합니다. 하지만 YouTube는 목록에 페이지를 매기므로 변수가 항상 즉시 모든 것을 포함하지는 않습니다. YouTube는 페이지 하단으로 스크롤할 때마다 더 많은 목록을 로드하지만 스크롤을 자동화할 수 있습니다.

ytInitialData 변수에 포함된 또 다른 데이터는 나머지 목록을 로드하는 데 필요한 API 토큰입니다. 그리고 목록이 완전히 로드되면 ytInitialData에서 토큰이 제거됩니다.

즉, 계속 아래로 스크롤할지 여부를 알기 위해 해당 토큰이 존재하는지 확인할 수 있습니다.

컨테이너의 높이<div>를 확인한 다음 함수window.scrollTo로 스크롤하여 페이지 하단으로 스크롤하는 스크립트를 작성했습니다.

그런 다음 이 목록에서 채널 ID와 채널 제목을 가져오는 스크립트를 작성했습니다. 채널 URL도 필요하지만 문자열"http://www.youtube.com/channel/" 뒤에 채널 ID를 추가하는 것만큼 쉬웠습니다. 그런 다음 모든 채널의 데이터를 하나씩 결합했습니다. 마지막으로 데이터를 콘솔에 기록합니다.

이 스크립트를 결합하여 함께 실행했습니다. 그것은 효과가 있었다.

조금 더 편리하게 하기 위해 CSV 데이터를 넣을 <div>를 만드는 또 다른 스크립트를 만들었습니다. 이 <div>position: fixed를 사용하여 화면을 덮습니다.

더 쉽게 사용할 수 있도록 텍스트를 파일로 저장하는 다운로드 버튼을 만들어 직접 복사하여 붙여넣을 필요가 없도록 했습니다.

스크립트



내 코드는 다음과 같습니다.

function getLast() {
  return ytInitialData.contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content.sectionListRenderer.contents.slice(-1)[0]
}
function canContinue() { return getLast().continuationItemRenderer != null }
(async () => {
  while (canContinue()) {
    let current = getLast().continuationItemRenderer.continuationEndpoint.continuationCommand.token;
    scrollTo(0, document.getElementById('primary').scrollHeight);
    while (canContinue() && current == getLast().continuationItemRenderer.continuationEndpoint.continuationCommand.token) {
      await new Promise(r => setTimeout(r, 100));
    }
  }
  scrollTo(0, 0);
  let floatDiv = document.createElement('div');
  let preText = document.createElement('pre');
  floatDiv.setAttribute('style', `position: fixed;
  background: #0f0f0f;
  z-index: 100000;
  inset: 2rem;
  overflow: auto;
  font-size: 2rem;
  white-space: pre;
  color: white;
  padding: 1rem;`);
  let csvText = "Channel Id,Channel Url,Channel Title\n" + ytInitialData.contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content.sectionListRenderer.contents.map(e => {
    if (!e.itemSectionRenderer) return;
    return e.itemSectionRenderer.contents[0].shelfRenderer.content.expandedShelfContentsRenderer.items
  }).flat().map(e => {
    if (e && e.channelRenderer) return `${e.channelRenderer.channelId},http://www.youtube.com/channel/${e.channelRenderer.channelId},${e.channelRenderer.title.simpleText}`;
    return '';
  }).join('\n');
  preText.innerText = csvText;
  let downloadLink = document.createElement('a');
  downloadLink.innerText = 'Download CSV';
  downloadLink.setAttribute('target', '_blank');
  downloadLink.setAttribute('style', `color: #bf3838;
  font-weight: bold;
  margin-bottom: 1rem;
  display: block;
  padding: 1rem;
  border-radius: 0.5rem;
  border: 2px solid #bf3838;
  width: fit-content;
  text-decoration: none;`);
  var t = new Blob([csvText], { type: "text/plain" });
  downloadLink.href = window.URL.createObjectURL(t)
  floatDiv.appendChild(downloadLink);
  floatDiv.appendChild(preText);
  document.body.appendChild(floatDiv);
})()


의 DevTools에서 실행할 수 있습니다. 그런 다음 "CSV 다운로드"를 클릭하여 파일을 저장할 수 있습니다.



결론



스크립트 작성을 완료할 때까지 Google 테이크아웃은 여전히 ​​내 구독 목록 다운로드를 보내지 않았습니다. 나는 결국 몇 시간 후에 이 다운로드를 받았지만 그 시점에서 나는 이미 내 목록을 NewPipe로 가져왔고 더 이상 그들의 목록이 필요하지 않았습니다.

내 생각에 Google 테이크아웃은 대기열에서 실행되어 각 요청에 대해 즉시 작업하지 않고 한 사람에게 데이터를 보낸 다음 다음 사람에게 데이터를 보냅니다. 이렇게 하면 약간의 비용을 절약할 수 있지만 많은 시간을 낭비하기도 합니다.

내 스크립트가 유용하기를 바랍니다. 개선 사항이 있으면 알려주세요! 이 게시물 아래의 토론이든, 이 스크립트에 대한 내GitHub gist의 의견이든, 심지어 에 대한 의견이든, 여러분이 이 스크립트로 무엇을 했는지 듣고 싶습니다.

좋은 웹페이지 즐겨찾기