Postes GALAXIE

Analyse automatique des tableaux de postes d'enseignants chercheurs sur GALAXIE

Pierre H. — 18 février 2014


In [36]:
import pandas
import urllib
from bs4 import BeautifulSoup
from IPython.display import HTML, display_html

Postes publiés dans GALAXIE (cf. page source)

Extrait de "Postes d'enseignants-chercheurs" :

Méthode de lecture HTML directe

pandas.read_html → cassé :-(


In [15]:
url = 'https://www.galaxie.enseignementsup-recherche.gouv.fr/ensup/ListesPostesPublies/Emplois_publies_TrieParCorps.html'

d = pandas.read_html(url, attrs={'class': 'tab'})


---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-15-28ddd0dc9952> in <module>()
      1 url = 'https://www.galaxie.enseignementsup-recherche.gouv.fr/ensup/ListesPostesPublies/Emplois_publies_TrieParCorps.html'
      2 
----> 3 d = pandas.read_html(url, attrs={'class': 'tab'})

/home/pierre/anaconda/lib/python2.7/site-packages/pandas/io/html.pyc in read_html(io, match, flavor, header, index_col, skiprows, infer_types, attrs)
    904                              'data (you passed a negative value)')
    905     return _parse(flavor, io, match, header, index_col, skiprows, infer_types,
--> 906                   attrs)

/home/pierre/anaconda/lib/python2.7/site-packages/pandas/io/html.pyc in _parse(flavor, io, match, header, index_col, skiprows, infer_types, attrs)
    773             break
    774     else:
--> 775         raise retained
    776 
    777     return [_data_to_frame(table, header, index_col, infer_types, skiprows)

AssertionError: No tables found

Méthode de parsing HTML semi-manuelle : BeautifulSoup

Lecture du fichier (et correction de malformation du html)


In [179]:
f = urllib.urlopen(url)

def fix_th(f):
    for line in f:
        if '<th' in line:
            line = line.replace('</td>', '</th>')
        yield line

s = ''.join(fix_th(f))
f.close()

#print(s[:2000])
len(s)


Out[179]:
316424

Parsing du HTML : attention au choix du parser !

  • 'html.parser' : OK (après avoir corrigé les "td" en "th")
  • 'lxml' : pas bon, il manque des lignes !
  • 'html5lib' : pas bon, on ne trouve pas de tableau !

In [182]:
soup = BeautifulSoup(s, 'html.parser')
print(soup.title.text)


Liste des postes d'enseignant-chercheur publiés et ouverts à la candidature à la date du 18/02/2014
tri par Corps / Section / Etablissement


In [183]:
tabs = soup.find_all('table')
# Les 2 tableaux imbriqués :
(len(tabs[0].find_all('tr', recursive=False)), 
 len(tabs[1].find_all('tr', recursive=False)) )


Out[183]:
(6, 345)

In [184]:
# Extraction des lignes :
rows = tabs[1].find_all('tr', recursive=False)
tr_head = rows[0]
rows = rows[1:]

# Affichage 1ère et dernière ligne du tableau
HTML('<table>{}{}</table>'.format(tr_head, ''.join(str(r) for r in rows[0:1]+rows[-1:])))


Out[184]:
UAI Etablissement Référence GALAXIE N° dans le SI local Article Corps Chaire Section Section2 Section3 Date de prise de fonction Date ouverture cand Date clôture cand Profil Localisation Etat de vacance
0350936C UNIVERSITE RENNES 1 4205 * 1238 26-I-1 MCF Non 1 01/09/2014 27/02/2014 01/04/2014 Droit social Rennes
0911101C UNIVERSITE PARIS 11 4231 * 46-3 PR Non 85 01/09/2014 27/02/2014 01/04/2014 Pharmacotechnie et Biopharmacie appliquées aux voies locales CHATENAY-MALABRY

In [148]:
head = [th.b.text for th in tr_head.find_all('th')]
print('nombre de colonnes : {}'.format(len(head)))
head


nombre de colonnes : 16
Out[148]:
[u'UAI',
 u'Etablissement',
 u'R\xe9f\xe9rence GALAXIE',
 u'N\xb0 dans le SI local',
 u'Article',
 u'Corps',
 u'Chaire',
 u'Section',
 u'Section2',
 u'Section3',
 u'Date de prise de fonction',
 u'Date ouverture cand',
 u'Date cl\xf4ture cand',
 u'Profil',
 u'Localisation',
 u'Etat de vacance']

In [185]:
# Vérification des lignes:
i = 0
for tr in rows:
    cols = tr.find_all('td')
    i+= 1
    assert len(cols) == 16
i


Out[185]:
344

Flitrage des lignes : sélection de la section 63


In [157]:
head[7:10]


Out[157]:
[u'Section', u'Section2', u'Section3']

In [177]:
def section_filter(rows, section):
    for tr in rows:
        cols = tr.find_all('td')
        row_sections = [td.text for td in cols[7:10]]
        row_sections = [int(n) for n in row_sections if n != '']
        if section in row_sections:
            yield tr

selected_rows = list(section_filter(rows, 63))
            
HTML('<table>{}{}</table>'.format(tr_head, ''.join(str(r) for r in selected_rows)))


Out[177]:
UAI Etablissement Référence GALAXIE N° dans le SI local Article Corps Chaire Section Section2 Section3 Date de prise de fonction Date ouverture cand Date clôture cand Profil Localisation Etat de vacance
0221809X UNIV. RENNES 1 (ENSSAT LANNION) 4251 * 26-I-1 MCF Non 30 63 01/09/2014 27/02/2014 01/04/2014 Enseignement à l¿Enssat (composants semi-conducteurs, optoélectronique, photonique, TP) Recherche ds UMR Foton-équipe systèmes photoniques (carac., bruit, dyn. non-linéaire, modélisation) LANNION
0911101C UNIVERSITE PARIS 11 4229 * 26-I-1 MCF Non 30 63 01/09/2014 27/02/2014 01/04/2014 Optique et Photonique INSTITUT D'OPTIQUE
0911101C UNIVERSITE PARIS 11 4241 * 26-I-1 MCF Non 61 63 01/09/2014 27/02/2014 01/04/2014 Traitement de l'information appliqué aux systèmes électroniques et électriques CACHAN
0751722P UNIVERSITE PARIS 6 (P. ET M. CURIE) 4266 * 1380 26-I-1 MCF Non 63 01/09/2014 27/02/2014 01/04/2014 Modélisation multiphysique de microsystèmes dans les réseaux WBAN Campus Jussieu
0751722P UNIVERSITE PARIS 6 (P. ET M. CURIE) 4267 * 0648 26-I-1 MCF Non 63 01/09/2014 27/02/2014 01/04/2014 Matériaux et dispositifs pour les systèmes autonomes et à faible consommation Campus Jussieu
0911101C UNIVERSITE PARIS 11 4226 * 26-I-1 MCF Non 63 01/09/2014 27/02/2014 01/04/2014 Instrumentation et méthodes en imagerie par résonance magnétique ORSAY
0221809X UNIV. RENNES 1 (ENSSAT LANNION) 4247 * 46-1 PR Non 30 63 01/09/2014 27/02/2014 01/04/2014 Enseignement à l¿Enssat,responsabilité pédagog.,recherche ds équipe Systèmes Photoniques,UMR CNRS Foton (nouvelles sources lasers,capteurs et/ou fonctions optiques, liens avec partenaires industr.) LANNION
0911101C UNIVERSITE PARIS 11 4230 * 46-1 PR Non 30 63 01/09/2014 27/02/2014 01/04/2014 Optique et Photonique INSTITUT D'OPTIQUE
0300930Y UNIV. MONTPELLIER 2 (IUT NIMES) 113 46-1 PR Non 63 01/09/2014 06/02/2014 08/03/2014 Électronique, Electrotechnique, Micro-électronique, Photonique, Instrumentation, Mesure, Simulation. IUT Nimes

In [ ]: