정당한 이유 없이 영화 등급 분포 그래프 작성

28043 단어 javascriptmovies
저는 이번 주에 휴가 중이고(Adobe에서 일할 때의 이점 중 하나는 연중 두 번의 종료입니다) 실제로 코드를 작성할 기회가 없었습니다(Black Ops 멀티플레이어에서 레벨을 연마하느라 바빴습니다). 하지만 어제 저는 무슨 일이 일어날지 보고 싶은 것 외에는 별 중요한 이유 없이 작은 데모 작업을 하고 있는 제 자신을 발견했습니다. 미국 이외 지역의 사람들에게 MPA(공식적으로는 MPAA)는 영화 협회입니다. 그들은 미국에서 개봉한 영화에 등급을 부여하는 일을 담당하고 있습니다. 이 등급에 대해 할 말이 많습니다. 아직 보지 못하셨다면 협회에서 제공하는 위선적인 등급에 대해 자세히 설명하는 "This Film is Not Yet Rated"을 적극 권장합니다.

등급 시스템 웹 사이트https://www.filmratings.com/에서 나 자신을 발견했고 특정 연도 및 등급에 대한 영화를 찾을 수 있는 검색 엔진이 있다는 것을 발견했습니다. 예를 들어, 내가 태어났을 때 개봉한 R 영화는 다음과 같습니다. https://www.filmratings.com/Search?filmYear=1973&filmRating=R&x=20&y=18

저는 브라우저에서 devtools를 열었고 웹 사이트가 데이터를 가져오기 위해 SOAP 기반 웹 서비스를 사용하고 있음을 발견했습니다. https://www.filmratings.com/Filmratings_CARA/WebCaraSearch/Service.asmx

저는 SOAP 웹 서비스를 좋아합니다. 그리고 사랑이라는 말은 정말 정말 싫어한다는 뜻입니다. 하지만 이전에 ( "Working with SOAP in a Node App" ) 그것들을 다뤘고 등급 분포가 수년에 걸쳐 어떻게 변하는지 보는 것이 흥미로울 것이라고 생각했습니다. 나는 웹 서비스가 한 페이지의 데이터와 함께 1년 동안의 총 영화 수 및 등급을 나타내는 값을 반환한다는 것을 알았습니다. 총계는 나에게 충분할 것입니다. 웹사이트를 가지고 놀면서 나는 내가 얻을 수 있는 가장 초기 데이터가 1968년이라는 것을 발견했고, 그것으로 1968년부터 2020년까지의 시청률 합계를 수집하는 스크립트를 만들었습니다.

등급 자체는 수년에 걸쳐 변경되었습니다. 예를 들어 PG-13은 1984년에 추가되었습니다. "GP"와 같은 일부는 제거되었습니다. "X"가 "NC-17"로 변경되었습니다. 내 스크립트의 경우 대부분의 사람들이 인식하는 "일반적인"등급에 초점을 맞추기로 결정했습니다.

저는 1년, 1등급을 얻기 위한 간단한 스크립트로 시작했습니다.

const soap = require('soap');
const apiWSDL = 'https://www.filmratings.com/Filmratings_CARA/WebCaraSearch/Service.asmx?WSDL';
const xml2js = require('xml2js');

(async () => {

    let year = 1968;
    let rating = 'G';

    let client = await soap.createClientAsync(apiWSDL);

    let result = await client.GetTitleListByYearRatingFullWithPaginationAsync({
        year: 1968,
        rating: 'G'
    });

    let parser = new xml2js.Parser();

    let xml = result[0]['GetTitleListByYearRatingFullWithPaginationResult'];
    //console.log(xml);
    let data = await parser.parseStringPromise(xml);
    let total = data.SearchResults.total_response[0];
    console.log(`There were ${total} ${rating} movies in ${year}`);

})();

soapxml2js 패키지를 사용하고 있습니다. soap 패키지는 웹 서비스와의 통신을 처리하고 xml2js는 최종 결과를 구문 분석하는 데 도움이 됩니다. 나는 영화의 이름이 아니라 총계에만 관심이 있다는 것을 기억하십시오. 이 작업을 완료한 다음 스크립트를 좀 더 일반적으로 만들었습니다.

const soap = require('soap');
const apiWSDL = 'https://www.filmratings.com/Filmratings_CARA/WebCaraSearch/Service.asmx?WSDL';
const xml2js = require('xml2js');
const parser = new xml2js.Parser();
let client;
const ratings = ['G', 'PG', 'PG-13', 'R', 'NC-17','X'];
const startYear = 1968;
const endYear = 2020;
const fs = require('fs');

const totalResult = [];

(async () => {

    for(let year=startYear; year <= endYear; year++) {
        let yearResult = { year, ratings:{} };
        for(let x=0; x < ratings.length; x++) {
            let rating = ratings[x];
            let total = await getTotal(year, rating);
            console.log(`There were ${total} ${rating} movies in ${year}`);
            yearResult.ratings[rating] = parseInt(total,10);
        }
        totalResult.push(yearResult);
    }

    fs.writeFileSync('./mparatings.json', JSON.stringify(totalResult), 'utf8');
    console.log('Wrote out the data.');

})();

async function getTotal(year, rating) {
    if(!client) client = await soap.createClientAsync(apiWSDL);
    let result = await client.GetTitleListByYearRatingFullWithPaginationAsync({
        year,
        rating
    });

    let xml = result[0]['GetTitleListByYearRatingFullWithPaginationResult'];
    //console.log(xml);
    let data = await parser.parseStringPromise(xml);
    let total = data.SearchResults.total_response[0];
    return total;
}


결과를 파일에 기록합니다. 내 생각은 데이터를 한 번만 "스크래핑"하는 것이었습니다. 결과를 가지고 노는 동안 API를 '남용'하고 공격하고 싶지 않았습니다. 다음은 결과가 표시되는 방식의 하위 집합입니다.

[
    {
        "year": 1968,
        "ratings": {
            "G": 181,
            "PG": 0,
            "PG-13": 0,
            "R": 49,
            "NC-17": 0,
            "X": 3
        }
    },
    {
        "year": 1969,
        "ratings": {
            "G": 175,
            "PG": 0,
            "PG-13": 0,
            "R": 77,
            "NC-17": 0,
            "X": 13
        }
    },
    // more years...
]


시원한. 그래서 이 시점에서 저는 제 모든 데이터를 가지고 있었고 그것을 차트로 작성하기만 하면 되었습니다. 같은 클라이언트 측 차트 작성 솔루션을 연속으로 두 번 이상 사용할 수 없는 것 같아서 ApexCharts이 무료이고 누적 막대 차트를 검색하면 표시되므로 선택했습니다. 나는 코드를 털어 놓을 것이지만 솔직히 나는 대부분 그들의 문서에서 잘라내어 붙여 넣었습니다. 다음은 빈 div인 HTML입니다.

<html>
<head>
</head>


<body>

<div id="chart"></div>

<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<script src="mpa_app.js"></script>

</body>
</html>


그리고 여기 코드가 있습니다. 대부분의 작업은 내가 만든 데이터를 ApexCharts가 원하는 형태로 번역하는 것입니다.

const ratings = ['G', 'PG', 'PG-13', 'R', 'NC-17','X'];

document.addEventListener('DOMContentLoaded', init, false);
async function init() {

    let req = await fetch('./mparatings.json');
    let data = await req.json();

    let allYears = data.map(d => {
        return d.year;
    });

    let series = [];
    data.forEach(d => {
        for(let rating in d.ratings) {
            let existingSeries = series.findIndex(d => {
                return d.name === rating;
            });
            if(existingSeries === -1) {
                series.push({name:rating, data:[]});
                existingSeries = series.length-1;
            }
            series[existingSeries].data.push(d.ratings[rating]);
        }
    });
    console.log(series);

    let options = {
        series,
        chart: {
            type: 'bar',
            height: '100%',
            stacked: true,
        },
        plotOptions: {
            bar: {
                horizontal: true
            },
        },
        stroke: {
          width: 1,
          colors: ['#fff']
        },
        title: {
          text: 'MPA Ratings by Years'
        },
        xaxis: {
          categories: allYears
        },
        yaxis: {
          title: {
            text: undefined
          },
        },
        fill: {
          opacity: 1
        },
        legend: {
          position: 'top',
          horizontalAlign: 'left',
          offsetX: 40
        }
    };

    let chart = new ApexCharts(document.querySelector("#chart"), options);
    chart.render();
}


결과는 다음과 같습니다.



읽기에 너무 작다는 것을 깨달았습니다. 웹 앱 자체를 여기에 올려 놓았습니다. https://static.raymondcamden.com/demos/mpa/mpa.html 이에 대해 궁금한 점이 있으면 연락주세요!

좋은 웹페이지 즐겨찾기