데이터 스크랩(Data scraping)

JSON 파일 추출하기 (2차 추출, jq 명령어)

json 파일은 key와 value 로 구성되어 있습니다. jq 명령어를 통해, key 의 계층구조를 주소찾듯이 차례대로 지정해주면 value값을 찾아낼수 있습니다. https://stedolan.github.io/jq/

이 명령어가 사실상 핵심부분입니다. 웹페이지의 복잡도에 따라 이 명령어도 같이 복잡해집니다.

일단 파일을 대충 훑어본뒤에, 가져올 정보의 key값이 무엇인지 알아내야 합니다.

 "html": {
        "body": {
            "tr": [
                {
                    "td": [
                        {
                            "class": "id_column",
                            "$t": "1"
                        },
                        {
                            "a": {
                                "href": "problem=1",
                                "title": "Published on Friday, 5th October 2001, 06:00 pm",
                                "$t": "Multiples of 3 and 5"
                            }
                        },
                        {
                            "div": {
                                "style": "text-align:center;",
                                "$t": "768062"
                            }
                        }
                    ]
                },

html>body>tr

앞에서 추출한 json 파일을 살짝 들여다 보면, 우리가 가져올 정보(id의 숫자, title의 문자열, solved의 숫자)는 html 키 밑에 body 키 밑에 tr 키값 밑에 있고, tr키는 배열[ ]형태로 여러개의 tr값이 존재합니다. 그중에 첫번째 tr 키만 가져올려면,

< test_table.json jq -c '.html.body.tr[0]'

0번째, 즉 첫번째 tr 의 내용만 모두 출력이 됩니다.

html>body>tr>td

그 하위의 td 값까지 정해줄려면, td 역시 배열 형태 [ ] 로 3개가 존재하기 때문에, 0번째 td 만 출력하면

< test_table.json jq -c '.html.body.tr[0].td[0]'

{"class":"id_column","$t":"1"}

첫번째 tr의 첫번째td 블럭이 출력됩니다.

 

첫번째가 아닌 모든 tr 이나 td 를 출력하려면, 인덱스값을 주지말고 빈칸으로 놔두면 됩니다.

첫번째 tr의 모든td(3개)를 출력하려면,

< test_table.json jq -c '.html.body.tr[0].td[]'

{"class":"id_column","$t":"1"}
{"a":{"href":"problem=1","title":"Published on Friday, 5th October 2001, 06:00 pm","$t":"Multiples of 3 and 5"}}
{"div":{"style":"text-align:center;","$t":"768062"}}

 

모든 tr의 첫번째 td[0]만 출력하고 싶으면,

< test_table.json jq -c '.html.body.tr[].td[0]'

{"class":"id_column","$t":"1"}
{"class":"id_column","$t":"2"}
{"class":"id_column","$t":"3"}
{"class":"id_column","$t":"4"}
{"class":"id_column","$t":"5"}
{"class":"id_column","$t":"6"}
{"class":"id_column","$t":"7"}
{"class":"id_column","$t":"8"}
{"class":"id_column","$t":"9"}
{"class":"id_column","$t":"10"}
{"class":"id_column","$t":"11"}
....

아마 이런형태, 큰부분에서 루프를 돌면서, 공통적인 작은 부분만 골라내는 형태가 보통 최종적으로 원하는 형태가 될겁니다.

 

html>body>tr>td>id

그다음 좀더 세부적으로 들어가서, td 아래 id 값은 "$t"라는 키에 들어있습니다.

$t는 특수문자를 포함하고 있어서, 따옴표를 해줘야 합니다.

< test_table.json jq -c '.html.body.tr[].td[0]."$t"'

 

html>body>tr>td>a>title

그다음 title 값은 td[]에서 한단계 더 내려가서 a 태그 혹은 "a" 키값 아래에 "$t" 키에 있습니다.
(a 혹은 "a" 어떤형태로든 써줘도 됩니다.)

< test_table.json jq -c '.html.body.tr[].td[0]."a"."$t"'

 

html>body>tr>td> |  id , a>title

id와 title 을 동시에 가져오려면

< test_table.json jq -c '.html.body.tr[] |.td[0]."$t", .td[1]."a"."$t"'

컴마로 차례로 연결해주면 되는데, 반복되는 앞부분은 파이프 앞부분에 써주고, 나머지 부분만 파이프 뒷부분에 써주면 됩니다.

 

결과를  json 형태로 표시하려면,

< test_table.json jq -c '.html.body.tr[] | {id:.td[0]."$t", title:.td[1]."a"."$t"'}

중괄호로 묶어주고, 각각의 출력값 앞에 key 값을 정해줄수 있습니다. 이 키값이 나중에 csv로 변환했을때 key값이 됩니다.

 

마찬가지로, 마지막solved 값도 동시에 가져올수 있습니다.

< test_table.json jq -c '.html.body.tr[] | {id:.td[0]."$t", title:.td[1]."a"."$t", solved:..td[2].div."$t"'}

세번째, solved 값은 td[2] 아래에 div 태그안에 들어있습니다.

{"id":"1","title":"Multiples of 3 and 5","solved":"768062"}
{"id":"2","title":"Even Fibonacci numbers","solved":"616688"}
{"id":"3","title":"Largest prime factor","solved":"441451"}
{"id":"4","title":"Largest palindrome product","solved":"392749"}
{"id":"5","title":"Smallest multiple","solved":"400765"}
{"id":"6","title":"Sum square difference","solved":"403170"}
{"id":"7","title":"10001st prime","solved":"345064"}
{"id":"8","title":"Largest product in a series","solved":"291209"}
{"id":"9","title":"Special Pythagorean triplet","solved":"294257"}
{"id":"10","title":"Summation of primes","solved":"269852"}

이 리스트가 두번째 추출의 결과물입니다.

이렇게 출력된 결과는 마찬가지로 test_list.json 파일로 저장해주겠습니다.

 

csv 파일로 변환하기(json2csv)

여기까지 변환됐으면,  json2csv 명령으로 csv 파일로 변환해줄수 있습니다.

< test_table.json json2csv -k id,subject,solved > test_list.csv 

-k 옵션은 변환할때 사용할 key 값만 지정해줄수 있습니다. 순서를 바꾸면, 출력할때 순서도 바껴서 출력됩니다.


1,Multiples of 3 and 5,768062
2,Even Fibonacci numbers,616688
3,Largest prime factor,441451
4,Largest palindrome product,392749
5,Smallest multiple,400765
6,Sum square difference,403170
7,10001st prime,345064
8,Largest product in a series,291209
9,Special Pythagorean triplet,294257
10,Summation of primes,269852
11,Largest product in a grid,195431
12,Highly divisible triangular number,182761

...

 

column 의 head 값을 붙여서 출력하려면 p 옵션을 붙여주면 됩니다.

< test_table.json json2csv -k id,subject,solved > test_list.csv 

id,title,solved
1,Multiples of 3 and 5,768062
2,Even Fibonacci numbers,616688
3,Largest prime factor,441451
4,Largest palindrome product,392749
5,Smallest multiple,400765
6,Sum square difference,403170
7,10001st prime,345064
8,Largest product in a series,291209
9,Special Pythagorean triplet,294257
10,Summation of primes,269852
11,Largest product in a grid,195431
12,Highly divisible triangular number,182761

 

header를 붙였으면 csvlook 명령을 통해서 나름 보기좋게 출력도 가능합니다.

< test_list.csv csvlook

|-----+---------------------------------------+---------|
|  id  | title                                           | solved  |
|-----+---------------------------------------+---------|
|  1  | Multiples of 3 and 5                  | 768062  |
|  2  | Even Fibonacci numbers                | 616688  |
|  3  | Largest prime factor                  | 441451  |
|  4  | Largest palindrome product            | 392749  |
|  5  | Smallest multiple                     | 400765  |
|  6  | Sum square difference                 | 403170  |
|  7  | 10001st prime                         | 345064  |
|  8  | Largest product in a series           | 291209  |
...
...

댓글

댓글 본문
버전 관리
nomadlife
현재 버전
선택 버전
graphittie 자세히 보기