JSON вэб-скрапінг даных
24 лістапада 2023
Катэгорыя: Артыкулы
Зменены: 24.11.2023
Меткі:
Тэма: ІР ІС
Частка 1 з 2.
Наступныя артыкулы тэмы:
 
Падчас працы над манаграфіяй у 2021 годзе я аналізаваў даныя аб інфармацыйных сістэмах і рэсурсах, якія зарэгістраваныя ў дзяржаўных рэгістрах. З той пары прайшло колькі часу і на старонках гэтага блога я паўтару аналіз, але з выкарыстаннем новых падыходаў і да аналізу і да візуалізацыі вынікаў.
Наш аналіз будзе складацца з серыі артыкулаў і гэты артыкул - першы з іх.
Цяжкасць з якой давялося сутыкнуцца напачатку - гэта тое, што даные прадстаўлены ў зручным выглядзе для вывучэння карыстальнікамі рэгістраў, але не аналітыкамі. У прыватнасці, ёсць магчымасць дадаваць ці прыбіраць калонкі, ажыццяўляць пошук па рэестрам, але няма зручнай магчымасці спампаваць усе запісы. Улічваючы, што запісы размешчаны ў фармаце JSON, то звычайныя метады вэб-скрапінгу не падыходзяць, напрыклад, амаль бескарысна бібліятэка Beautiful Soup.
Тым не менш, фармат JSON на практыцы нават зручней, бо загружае ўсе запісы ў браўзер.
Тут і надалей мы праводзім аналіз з дапамогай Python у Jupyter Notebook.
Спачатку загружаем неабходныя бібліятэкі.
import pandas as pd
import requests
import json
import os
Information Systems
Збіраем інфармацыю з браўзера Chrome каб усталяваць аўтаматычнае злучэнне.
# У браўзеры Chrome хлядзім тут: inspector (network -> Fetch/XHR > Headers and Responce)
endpoint_sys = 'http://xn--c1akxf.xn--90ais/api/systemRegister/list'
header_sys = {'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'en-US,en;q=0.9',
'Connection': 'keep-alive',
'Content-Type': 'application/json; charset=UTF-8',
'Origin': 'http://xn--c1akxf.xn--90ais',
'Referer': 'http://xn--c1akxf.xn--90ais/app/registerIS',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64)\
AppleWebKit/537.36 (KHTML, like Gecko)\
Chrome/114.0.0.0 Safari/537.36'}
# інфармацыю для запыту капіруем як cURL, але нам патрэбна толькі некалькі строк кода
query_sys = f'{{"page":1,"rows":-1}}' # таксама звяртаю ўвагу на падвоаенне гэтых "{" дужак
Пераходзім да непасрэднай загрузкі даных.
response_sys = requests.post(endpoint_sys, headers=header_sys, data=query_sys)
# на старонцы адказу мы бачым, што толькі калонка 'rows' утрымлівае даные, таму абмяжоўваем запыт
parsed_sys = json.loads(response_sys.content)['rows']
# пераўтвараем даныя JSON у DataFrame
inf_sys = pd.DataFrame.from_dict(data=parsed_sys)
# пералічваем неабходныя для аналізу калонкі
columns_sys = ['numberOnRegistration', 'dateOnRegistration', 'dateActyalization',\
'dateExclude', 'stateNotstateName', 'fullNameIs', 'shortNameIs',\
'appointmentIs', 'functionIs', 'nameViewsIs', 'nameViewsStructures',\
'nameSizeIs', 'clientsName', 'operatorsName', 'ownersName',\
'developersName', 'proprietorsName']
# абмяжоўваем DataFrame неабходнымі калонкамі
inf_sys = inf_sys[columns_sys]
# пераўтвараем фармат даных, якія змяшчаюць даты ў фармат даты і часу
date_sys = ['dateOnRegistration', 'dateActyalization', 'dateExclude']
inf_sys[date_sys] = inf_sys[date_sys].apply(pd.to_datetime, format='%d.%m.%Y')
print(inf_sys.info()) # выводзім на экран інфармацыю пра DataFrame, які атрымаўся
Націснуўшы кнопку ніжэй можна паглядзець выніковы DataFrame.
паказаць інфармацыю
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 435 entries, 0 to 434
Data columns (total 17 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 numberOnRegistration 435 non-null object
1 dateOnRegistration 435 non-null datetime64[ns]
2 dateActyalization 111 non-null datetime64[ns]
3 dateExclude 38 non-null datetime64[ns]
4 stateNotstateName 435 non-null object
5 fullNameIs 435 non-null object
6 shortNameIs 435 non-null object
7 appointmentIs 435 non-null object
8 functionIs 435 non-null object
9 nameViewsIs 433 non-null object
10 nameViewsStructures 434 non-null object
11 nameSizeIs 433 non-null object
12 clientsName 417 non-null object
13 operatorsName 356 non-null object
14 ownersName 434 non-null object
15 developersName 434 non-null object
16 proprietorsName 435 non-null object
dtypes: datetime64[ns](3), object(14)
memory usage: 57.9+ KB
None
Захоўваем атрыманы DataFrame у файл, каб не пампаваць яго наноў.
os.makedirs('data', exist_ok=True)
inf_sys.to_csv('data/inf_sys.csv')
У наступных пастах мы будзем пачынаць аналіз менавіта з загрузкі гэтага файла.
Information Resources
У Беларусі, згодна з заканадаўствам, рэгістрацыі падлягаюць і інфармацыйныя сістэмы і рэсурсы. Таму каб іх прааналізаваць, трэба паўтарыць зробленыя вышэй аперацыі. Змяняем толькі вэб-адрас.
# repeat previous steps
endpoint_res = 'http://xn--c1akxf.xn--90ais/api/resourceRegister/list'
header_res = {'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'en-US,en;q=0.9',
'Connection': 'keep-alive',
'Content-Type': 'application/json; charset=UTF-8',
'Origin': 'http://xn--c1akxf.xn--90ais',
'Referer': 'http://xn--c1akxf.xn--90ais/app/registerIR',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64)\
AppleWebKit/537.36 (KHTML, like Gecko)\
Chrome/114.0.0.0 Safari/537.36'}
query_res = f'{{"page":1,"rows":-1}}'
Інфармацыйных сістэм зарэгістравана некалькі сотняў, а вось рэсурсаў - больш за 35 тысяч, таму вэб-скрапінг можа заняць некалькі хвілін. Аб’ём даных складае больш за гігабайт.
response_res = requests.post(endpoint_res, headers=header_res, data=query_res)
parsed_res = json.loads(response_res.content)['rows']
inf_res = pd.DataFrame.from_dict(data=parsed_res)
columns_res = ['numberOnRegistration', 'dateOnRegistration', 'dateActualization',\
'dateExclude', 'fullNameSource', 'shortNameSource', 'dbDepart', 'rtypeName',\
'themesName', 'rubricName', 'content', 'dbSizeMb', 'dbSizeRec', 'dbLang',\
'dbCreate', 'dbRetroBeg', 'dbRetroEnd', 'datasource', 'niokrFlag', 'niokrName',\
'bePart', 'relationFlag', 'relation', 'programmShell', 'safetyRequirements',\
'dtiBaseInfo', 'rstatus', 'dataChangeRstatus', 'dbDelivery', 'ownerName',\
'developersName', 'placesName', 'urlsName', 'serviceName', 'securitiesName',\
'informationObjectsInfo']
inf_res = inf_res[columns_res]
date_res = ['dateOnRegistration', 'dateActualization', 'dateExclude', 'dtiBaseInfo',\
'dataChangeRstatus']
inf_res[date_res] = inf_res[date_res].apply(pd.to_datetime, format='%d.%m.%Y')
print(inf_res.info()) # выводзім на экран інфармацыю пра DataFrame, які атрымаўся
Падрабязную інфармацыю пра DataFrame можна паглядзець ніжэй.
паказаць інфармацыю
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 36442 entries, 0 to 36441
Data columns (total 36 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 numberOnRegistration 36442 non-null object
1 dateOnRegistration 36442 non-null datetime64[ns]
2 dateActualization 5975 non-null datetime64[ns]
3 dateExclude 2534 non-null datetime64[ns]
4 fullNameSource 36442 non-null object
5 shortNameSource 36442 non-null object
6 dbDepart 33664 non-null object
7 rtypeName 36442 non-null object
8 themesName 36442 non-null object
9 rubricName 36442 non-null object
10 content 36436 non-null object
11 dbSizeMb 36183 non-null object
12 dbSizeRec 1656 non-null object
13 dbLang 36396 non-null object
14 dbCreate 36420 non-null object
15 dbRetroBeg 33881 non-null object
16 dbRetroEnd 16794 non-null object
17 datasource 29602 non-null object
18 niokrFlag 35994 non-null float64
19 niokrName 1046 non-null object
20 bePart 1356 non-null object
21 relationFlag 35936 non-null float64
22 relation 1824 non-null object
23 programmShell 36286 non-null object
24 safetyRequirements 16775 non-null object
25 dtiBaseInfo 36382 non-null datetime64[ns]
26 rstatus 36442 non-null object
27 dataChangeRstatus 36442 non-null datetime64[ns]
28 dbDelivery 16688 non-null object
29 ownerName 36440 non-null object
30 developersName 35898 non-null object
31 placesName 32446 non-null object
32 urlsName 12592 non-null object
33 serviceName 32427 non-null object
34 securitiesName 5274 non-null object
35 informationObjectsInfo 839 non-null object
dtypes: datetime64[ns](5), float64(2), object(29)
memory usage: 10.0+ MB
None
Захоўваем атрыманы DataFrame у файл.
os.makedirs('data', exist_ok=True)
inf_res.to_csv('data/inf_res.csv')
Памер файла атрымаўся 82,8 мегабайта, значна меней, чым у арыгінале. Такая розніца тлумачыцца тым, што шмат звестак, не патрэбных для аналізу, не захоўваецца. Напрыклад інфармацыя аб імёнах і кантактах працаўнікоў арганізацый, якія гэтыя звесткі ў рэгістр унеслі.
Такім чынам, мы спампавалі для аналізу звесткі, якія знаходзяцца ў вольным доступе, аб зарэгістраваных інфармацыйных сістэмах і рэсурсах. Больш за тое, мы правялі папярэднюю ачыстку даных ад звестак, якія нам не патрэбны і змянілі фармат даных для дат. У наступным артыкуле мы працягнем больш грунтоўна праводзіць ачыстку даных і паглядзім на найбольш перспектыўныя звесткі.