관련 지식
chrome, extension, webRequestBlocking, adblock

인터넷 사이트 중 광고가 많은 곳을 꼽으라고 한다면 단연코 뉴스 사이트를 꼽을 수 있습니다. 옛날처럼 돈을 내고 신문을 구독하는 시대가 아니다보니 회사를 유지하기 위하여 뉴스 글에 광고를 게재하는 것은 충분히 이해할 수 있지만 일부 뉴스 사이트는 도가 지나칠 정도의 광고를 게재하고 있습니다. 특히 성인이 봐도 눈쌀이 찌푸려지는 성인광고를 노골적으로 보여주는 곳도 있구요.

제 사이트의 이전 글을 보신 분이라면 크롬의 확장 프로그램을 만들었던 것을 기억하실 겁니다. 광고 차단 확장프로그램을 설치하면 간단하게 깨끗한 뉴스를 볼 수 있지만, 이왕만든 확장프로그램을 확장해서 내가 원하는 입맛대로 광고를 차단해보는 것도 재밌을것 같습니다. 이 방식을 응용하면 광고가 아닌 다른 것도 차단 가능합니다.

차단 방법

광고를 차단할 방법에 대해 생각해보겠습니다. 방법은 두가지가 있을것 같습니다.

  1. 뉴스사이트에서 호출하는 리소스에서 광고사이트와 관련된 문자열을 지운다.
  2. 광고 사이트 URL을 호출할 때 호출을 cancel 한다.

각가 장단점이 있습니다. 1번 방법의 경우 가장 완벽한 차단이 가능하지만 각 뉴스 사이트의 소스를 분석해서 적용해야 하므로 꽤 많은 시간이 필요합니다. 2번 방법의 경우 뉴스 사이트에서 광고 사이트의 js, html 등을 Request 할때 cancel 시키는 방법이므로 비슷한 유형으로 적용된 광고는 뉴스 사이트에 상관없이 차단이 가능합니다. 하지만 만약 해당 사이트를 내가 이용해야할 경우에도 cancel 될수 있으므로 주의해야 합니다.

하지만 2번 방식이 가장 간단한 방식이므로, 그 방식으로 차단하도록 해보겠습니다.

아래 이미지는 오마이뉴스의 뉴스 기사 하나를 조회했을때를 크롬의 개발자 도구로 확인한 모습입니다.

페이지 안에 있는 모든 리소스를 로딩하는데 9초 정도의 시간이 걸린것을 볼 수 있습니다. 많은 광고는 기사를 볼때도 불편하지만 로딩 속도도 저하시키고, 많은 네트워크 트래픽을 사용합니다. 이 모습이 어떻게 바뀔까요?

manifest.json 설정

확장 프로그램을 만들때는 항상 manifest.json 파일 설정이 필요합니다. 이전에는 webRequest 만 썼는데 이번엔 권한에 webRequestBlocking 이 추가되었습니다. request cancel 을 위해 반드시 필요합니다.

  1. {
  2. "name": "adblock",
  3. "version": "0.0.1",
  4. "manifest_version": 2,
  5. "description": "",
  6. "background": {
  7. "scripts": [
  8. "adblock.js"
  9. ],
  10. "persistent": true
  11. },
  12. "browser_action": {
  13. "default_title": "adblock"
  14. },
  15. "permissions": [
  16. "background",
  17. "tabs",
  18. "webRequest",
  19. "webRequestBlocking",
  20. "https://*/*",
  21. "http://*/*"
  22. ]
  23. }

adblock.js

manifest.js에서 설정한 adblock.js를 만들 차례입니다.

  1. let blockUrls = [
  2. 'http://adf.acrosspf.com/*',
  3. 'http://static.criteo.net/*',
  4. 'http://adc.ohmynews.com/*',
  5. 'http://fs.bizspring.net/*',
  6. 'https://static.xx.fbcdn.net/*',
  7. 'https://www.google.co.kr/ads/*',
  8. 'http://www.ohmynews.com/NWS_Web/Common/JS/GoogleAnalytics.js',
  9. 'http://www.ohmynews.com/NWS_Web/Common/JS/GoogleAnalytics_PC.JS',
  10. 'http://www.ohmynews.com/NWS_Web/Common/JS/TagManager.JS',
  11. 'http://ojsimg.ohmynews.com/2012_ad_rolling.htm?*',
  12. 'http://adx-exchange.toast.com/*',
  13. ];
  14. chrome.webRequest.onBeforeRequest.addListener(
  15. function(info) {
  16. return {cancel: true};
  17. },
  18. // filters
  19. {
  20. urls: blockUrls
  21. },
  22. // extraInfoSpec
  23. ["blocking"]
  24. );

소스는 매우 심플합니다. info 변수의 값을 조사하여 차단 해야할(호출을 취소 할) URL일 경우 취소하면 되지만 이것은 그보다 더 심플합니다. onBeforeRequest 의 이벤트 리스너는 어떤 URL에 대해서 작업을 수행할 것인지 대상을 filter 할 수 있습니다. 즉 filter 에 지정된 URL일 경우에만 콜백함수가 호출되는 것입니다.

즉 위 코드는 지정된 URL에 해당하면 콜백함수가 호출될 것이고 콜백함수는 무조건 URL 호출을 cancel 하도록 리턴합니다. 간단하죠?

결과

위와 같이 만들면 필요한 코딩은 끝난것입니다. 저렇게 만들어진 확장 프로그램을 크롬에 추가하고 동일한 뉴스 기사를 로딩해 보겠습니다.

뉴스기사 사방이 이상하게 표시되고 있습니다. 본래는 html, js 등을 호출하여 광고가 보였어야 할 영역이지만 호출을 취소해 버렸기 때문에 에러처럼 표시된 것입니다.
개발자도구의 네트워크 탭을 보면 status 항목이 ‘(blocked:other)’ 로 보이는 리소스들이 있습니다. 위에서 만든 코드에 의해 request 가 cancel 된 것입니다. 취소된 리소스는 response 받을 데이터가 없으므로 네트워크를 거의 사용하지 않습니다. 따라서 화면을 로딩하는데 걸린 속도도 5초 정도로, 기존 로딩 속도보다 2배정도 빨라졌습니다.

정리

filter 에 URL을 지정할 때는 한가지 주의사항이 있습니다. 위 소스에서는 http://adf.acrosspf.com/* 와 같이 * 를 사용했지만 filter에 http://*.acrosspf.com/* 처럼 중간에는 사용할 수가 없습니다. URL 규칙에 정규표현식을 쓰는것도 불가능합니다. 만약 그러한 규칙을 적용해야 하는 상황이라면 filter 에서 URL 설정을 빼고, 호출하려는 모든 request 항목에 대해 URL 패턴을 직접 검증후 request cancel 여부를 판단해야 할 것입니다. 그렇지 않다면 아래처럼 오류가 나는것을 보시게 될 것입니다.