def test_first_from_list(Html): row = Html(['<div><a name="1">a</a><a name="2">b</a></div>']) qry = html.Select(databot.first('a:text')) with pytest.raises(html.SelectorError): qry(row) qry = html.Select(databot.first(['a:text'])) assert qry(row) == 'a'
def test_first_empty_string(Html): row = Html(['<div><a name="1">a</a><a name="2"></a></div>']) qry = html.Select(databot.first('a[name="2"]:text', 'a[name="1"]:text')) assert qry(row) == 'a'
def test_first_value(Html): row = Html(['<div><a name="1">a</a><a name="2"></a></div>']) qry = html.Select(databot.first('#missing?', value('z'))) assert qry(row) == 'z'
def run(bot): if bot.run('2007'): start_url = 'http://www.vrk.lt/statiniai/puslapiai/2007_savivaldybiu_tarybu_rinkimai/lt/savivaldybes.html' with bot.pipe('savivaldybių rinkimai 2007').append(start_url).dedup(): with bot.pipe('savivaldybių sąrašo puslapiai 2007').download(): with bot.pipe('savivaldybių rezultatų nuorodos 2007').select(['table.partydata tr td b > a@href']).dedup(): # noqa with bot.pipe('savivaldybių rezultatų puslapiai 2007').download(): bot.pipe('tarybos nariai').select(join( [ 'xpath://table[contains(@class,"partydata")][1]/tbody/tr[count(td)=3]', ( 'tr > td[2] > a@href', call(split_name, { 'sąrašas': 'tr > td[1]:text', 'pavardė vardas': 'tr > td[2] > a:text', 'nuo': first('tr > td[3]:text', value('2007-03-04')), 'iki': value('2011-02-26'), 'mandato panaikinimo priežastis': value(None), 'savivaldybė': call(fix_municipality_names, '/font[size="5"] > b:text'), 'kadencija': value(2007), }) ) ], [ 'xpath://table[contains(@class,"partydata")][2]/tbody/tr[count(td)=5]', ( 'tr > td[2] > a@href', call(split_name, { 'sąrašas': 'tr > td[1]:text', 'pavardė vardas': 'tr > td[2] > a:text', 'nuo': first('tr > td[3]:text', value('2007-03-04')), 'iki': first('tr > td[4]:text', value('2011-02-26')), 'mandato panaikinimo priežastis': 'tr > td[5]:text', 'savivaldybė': call(fix_municipality_names, '/font[size="5"] > b:text'), 'kadencija': value(2007), }) ) ], )) if bot.run('2011'): start_url = 'http://www.2013.vrk.lt/2011_savivaldybiu_tarybu_rinkimai/output_lt/savivaldybiu_tarybu_sudetis/savivaldybes.html' # noqa with bot.pipe('savivaldybių rinkimai 2011').append(start_url).dedup(): with bot.pipe('savivaldybių sąrašo puslapiai 2011').download(): with bot.pipe('savivaldybių rezultatų nuorodos 2011').select(['table.partydata tr td b > a@href']).dedup(): # noqa with bot.pipe('savivaldybių rezultatų puslapiai 2011').download(): bot.pipe('tarybos nariai').select(join( [ 'xpath://table[contains(@class,"partydata")][1]/tr[count(td)=3]', ( 'tr > td[2] > a@href', call(split_name, { 'sąrašas': 'tr > td[1]:text', 'pavardė vardas': 'tr > td[2] > a:text', 'nuo': first('tr > td[3]:text', value('2011-02-27')), 'iki': value('2015-02-28'), 'mandato panaikinimo priežastis': value(None), 'savivaldybė': call(fix_municipality_names, '/font[size="5"] > b:text'), 'kadencija': value(2011), }) ) ], [ 'xpath://table[contains(@class,"partydata")][2]/tr[count(td)=5]', ( 'tr > td[2] > a@href', call(split_name, { 'sąrašas': 'tr > td[1]:text', 'pavardė vardas': 'tr > td[2] > a:text', 'nuo': first('tr > td[3]:text', value('2011-02-27')), 'iki': first('tr > td[4]:text', value('2015-02-28')), 'mandato panaikinimo priežastis': 'tr > td[5]:text', 'savivaldybė': call(fix_municipality_names, '/font[size="5"] > b:text'), 'kadencija': value(2011), }) ) ], )) if bot.run('2015'): start_url = 'http://www.2013.vrk.lt/2015_savivaldybiu_tarybu_rinkimai/output_lt/savivaldybiu_tarybu_sudetis/savivaldybes.html' # noqa with bot.pipe('savivaldybių rinkimai').append(start_url).dedup(): with bot.pipe('savivaldybių sąrašo puslapiai').download(): with bot.pipe('savivaldybių rezultatų nuorodos').select(['table.partydata tr td b > a@href']).dedup(): with bot.pipe('savivaldybių rezultatų puslapiai').download(): bot.pipe('tarybos nariai').select(join( [ 'xpath://table[contains(@class,"partydata3")][1]/tr[count(td)>0]', ( 'tr > td[2] > a@href', call(split_name, { 'sąrašas': 'tr > td[1]:text', 'pavardė vardas': 'tr > td[2] > a:text', 'nuo': 'tr > td[3]:text', 'iki': value('2019-03-01'), 'mandato panaikinimo priežastis': value(None), 'savivaldybė': '/font[size="5"] > b:text', 'kadencija': value(2015), }) ) ], [ 'xpath://table[contains(@class,"partydata3")][2]/tr[count(td)>0]', ( 'tr > td[2] > a@href', call(split_name, { 'sąrašas': 'tr > td[1]:text', 'pavardė vardas': 'tr > td[2] > a:text', 'nuo': 'tr > td[3]:text', 'iki': 'tr > td[4]:text', 'mandato panaikinimo priežastis': 'tr > td[5]:text', 'savivaldybė': '/font[size="5"] > b:text', 'kadencija': value(2015), }) ) ], )) bot.compact() bot.pipe('tarybos nariai').export('data/vrk/savivaldybiu-tarybu-sudetis/tarybos-nariai.csv')
def run(bot): bot.download_delay = 7 # seconds, vtek.lt denies access if more frequent request are detected start_urls = [ # Seimas (kodas: 188605295) 'http://www.vtek.lt/paieska/id001/paieska.php?dekl_jkodas=188605295&dekl_vardas=&dekl_pavarde=&rasti=Surasti', # Europos parlamentas (kodas: 188648923) 'http://www.vtek.lt/paieska/id001/paieska.php?dekl_jkodas=188648923&dekl_vardas=&dekl_pavarde=&rasti=Surasti', ] # Download all pagination pages, redownload after each 7 days with bot.pipe('sąrašas').clean(timedelta(days=7)).append(start_urls).dedup(): with bot.pipe('puslapiai').download(): with bot.pipe('sąrašas').select(['.panel-body > a@href']).dedup(): with bot.pipe('puslapiai').download(): # We don't want to select page links from each page, they are the same on each page. bot.pipe('sąrašas').skip() # Download declaraton pages and group by full name, since URL's are changing with bot.pipe('puslapiai'): with bot.pipe('seimo nariai').clean(timedelta(days=30)).select(call(select_by_code, [ 'xpath://div[contains(@class,"panel-body") and count(div)=3]', ( 'div[1] > a:text', { # Person's full name 'link': 'div[1] > a@href', # Link to declaration page 'code': strip('div[2]:text'), # Position code in an institution where this person work 'institution': 'div[3]:text', # Link to declaration page } ) ])).dedup(): bot.pipe('seimo narių deklaracijų puslapiai').download( row.value['download'], headers={'Referer': row.value['download']} ) # Extract row data for members of parlament with bot.pipe('seimo narių deklaracijų puslapiai'): bot.pipe('seimo narių deklaracijos').select( nspace(lower('#asmens_duomenys xpath:./tr[contains(td/text(),"DEKLARUOJANTIS ASMUO")]/following-sibling::tr[1]/td/text()')), { # noqa 'vtek link': row.key, 'deklaruojantis asmuo': '#asmens_duomenys xpath:./tr[contains(td/text(),"DEKLARUOJANTIS ASMUO")]/following-sibling::tr[1]/td/text()', # noqa 'darbovietė': '#asmens_duomenys xpath:./tr[contains(td/text(),"DARBOVIETĖ")][1]/following-sibling::tr[1]/td/text()', # noqa 'pareigos': '#asmens_duomenys xpath:./tr[contains(td/text(),"PAREIGOS")][1]/following-sibling::tr[1]/td/text()', # noqa 'sutuoktinis': '#asmens_duomenys xpath:./tr[contains(td/text(),"SUTUOKTINIS, SUGYVENTINIS, PARTNERIS")]/following-sibling::tr[2]/td/text()?', # noqa 'sutuoktinio darbovietė': '#asmens_duomenys xpath:./tr[contains(td/text(),"SUTUOKTINIO, SUGYVENTINIO, PARTNERIO DARBOVIETĖ")]/following-sibling::tr[1]/td/text()?', # noqa 'sutuoktinio pareigos': '#asmens_duomenys xpath:./tr[contains(td/text(),"PAREIGOS")][2]/following-sibling::tr[1]/td/text()?', # noqa 'deklaracijos': [ '#pagrindine_priedai #p_virsus', ( strip('tr[2] > td:text'), [ 'xpath:./../../following-sibling::tr[1]/td/table[@id="priedas"]/tr/td/table/tr', ( first(strip('td[1]:text'), value(None)), # Field name first(strip('td[2]:text?'), value(None)), # Field value ) ] ) ] } ) # Extract all kinds of declarations, export them to csv and upload to the server extract_args = [ ('sandoriai', ('SANDORIAI', 'Sandorį sudaręs asmuo', {('Sandoris', None)})), ('juridiniai', ('RYŠIAI SU JURIDINIAIS ASMENIMIS', 'Asmuo, kurio ryšys nurodomas')), ('fiziniai', ('RYŠIAI SU FIZINIAIS ASMENIMIS', 'Asmuo, kurio ryšys nurodomas')), ('individuali veikla', ('INDIVIDUALI VEIKLA', 'Asmuo, kurio individuali veikla toliau bus nurodoma')), ('kita', ('KITI DUOMENYS, DĖL KURIŲ GALI KILTI INTERESŲ KONFLIKTAS', None)), ] for name, args in extract_args: csvpath = 'data/%s.csv' % name.replace(' ', '-') with bot.pipe('seimo narių deklaracijos'): if bot.pipe(name).is_filled(): bot.pipe(name).clean().reset().call(extract(*args)).export(csvpath) subprocess.call(['scp', csvpath, 'atviriduomenys.lt:/opt/atviriduomenys.lt/app/var/www/data/vtek/seimas']) # noqa bot.compact()
#!/usr/bin/env python3 from databot import Bot, define, task, first pipeline = { 'pipes': [ define('index'), define('news'), ], 'tasks': [ task('index').once().download('https://www.reddit.com/'), task('index', 'news').select([ '.thing.link', ('.entry .title > a@href', { 'title': '.entry .title > a:text', 'score': '.midcol .score.likes@title', 'time': first(['.tagline time@datetime']), 'comments': '.entry a.comments:text', }) ]), task('news').export('/tmp/reddit.jsonl'), task().compact(), ], } if __name__ == '__main__': Bot('/tmp/reddit.db').main(pipeline)
#!/usr/bin/env python3 from databot import Bot, define, task, first pipeline = { 'pipes': [ define('index'), define('news'), ], 'tasks': [ task('index').once().download('https://www.reddit.com/'), task('index', 'news').select([ '.thing.link', ( '.entry .title > a@href', { 'title': '.entry .title > a:text', 'score': '.midcol .score.likes@title', 'time': first(['.tagline time@datetime']), 'comments': '.entry a.comments:text', } ) ]), task('news').export('/tmp/reddit.jsonl'), task().compact(), ], } if __name__ == '__main__': Bot('/tmp/reddit.db').main(pipeline)