Package: api-offres-emploi
api-offres-emploiA python wrapper forAPI Offres d'emploi v2available onEmploi Store(Pole Emploi).Table of content1. Setting up2. UsageInstallationAuthentification3. Examples3.1. search3.2. referentiel4. Analysis of the search output4.1. Aggregate view of job offers4.2. Detailed view of job offers1. Setting upTo use the API, you need to subscribe to theApi Offres d'emploi v2. Here are the steps:Create an account onEmploi storeGo to the dashboard (Tableau de bord) and create an application. You should then have the client ID (Identifiant) and client secret key (Clé secrète).Go tocatalogueand subscribe toApi Offres d'emploi v22. Usage2.1. InstallationThe package can be installed via pip:pipinstallapi-offres-emploi2.2. AuthentificationTo authentificate, create an instance ofApiwith your client id and secrets (you might want to access these two variables through environment variables instead of hardcoding them):fromoffres_emploiimportApiclient=Api(client_id="<your client id>",client_secret="<your client secret>")2.3. Methods exposed by the API 'Offres d'emploi v2'The APIOffres d'emploi v2has two methods :search: return aggregate count (namedfiltresPossibles) of the job offers along with the detailed list of these job offers (namedresultats). A lot of parameters are available : date, keywords, localization, etc. Extensive information on the website pageRechercher par critères.referentiel: return reference source (more information on the website pageRéférentiels).About range and pagination: In the methodsearch, only the first 150 job offers are returned by default by the API (since the defaultrangevalue is0-149). There are three constraints regarding therangeparameter (see the reference for the parameter 'range'):the maximal value for the first element of range is 1000the maximal value for the second element of range is 1149the number of result for a given requests must be inferior or equals to 150Hence for a given search, it is possible to get up to 1150 job offers, by modifying the value of the parameterrangefor each request (0-149then150-299,300-449, etc.). However somesearchmight have much more than 1150 job offers. In this case one has to narrow down the search using additional parameters (for instance: by playing with the parametersminCreationDateandmaxCreationDateof the request).Limit rate: The API limit rate is set to 3 requests per second.Equivalence between theAPI Offres d'emploi v2methods and this module methods: The 2 main methods fromApi Offres d'emploi v2have the same name in the python module (searchandreferentiel) and are methods of the module classApi. One notable difference is that the output ofsearchof this module has an additionalContent-Rangeentry (describe hereafter).3. Examples3.1. SearchMinimal example of searchTheAPI Offres d'emploi v2has default parameters, so we can make a requests without parameters (will return the latest job offers) :basic_search=client.search()The output of the module'sApi.searchmethod is the same as theApi Offres d'emploi v2(dictionnary with entriesfiltresPossiblesandresultats) with an additional entry,Content-Range, that gives the first and last index used for therangeparameter along with the total number of available job offers for this request. For instance :basic_search['Content-Range']will output :{'first_index':'0','last_index':'149','max_results':'300749'}The other fields (filtresPossiblesandresultats) are explored further thesection 4.A more complex searchA more sensible approach would be to search for special keyword over a certain period, for instance the job offers with that include the keywordbig datasince 2020-03-01 at 12h30.fromoffres_emploi.utilsimportdt_to_str_isoimportdatetimestart_dt=datetime.datetime(2020,3,1,12,30)end_dt=datetime.datetime.today()params={"motsCles":"data science",'minCreationDate':dt_to_str_iso(start_dt),'maxCreationDate':dt_to_str_iso(end_dt)}search_on_big_data=client.search(params=params)The full list of parameters for thesearchrequest are available in the pageRechercher par critères. These parameters are passed as dictionary to the parameterparams. Note that the keys of this dictionnary are in camelCase, as in theAPI Offres d'emploi v2specification. Also, we feed adatetimeobject to the helper functiondt_to_str_isoto convert it to a string with the appropriateISO-8601format required by the API.3.2. ReferentielGetting reference source (referentielin french) is more straightforward since it does not need any parameter ; one just need to specify the desired reference source:referentiel_metiers=client.referentiel('metiers')It will output the following list of dictionnaries:[{'code':'1','libelle':"Métiers de l'environnement et du développement durable"},{'code':'2','libelle':'Métiers de la défense et de la sécurité publique (hors logistique, santé, tertiaire, restauration)'},{'code':'3','libelle':"Métiers du patrimoine et de la restauration d'oeuvres d'art"},{'code':'4','libelle':"Métiers de l'intelligence économique"},{'code':'5','libelle':'Métiers de la recherche'},...]The full list ofreferentielis available in the docstring of the method or in theRéférentiel pageof the API.4. Analysis of the search outputThe output of theApi.searchis a dictionary with three entries:filtresPossiblesresultatsContent-RangeThe breakdown of the available job offers into different categories (type of contract, experience, qualification, nature of contract) are available in thefiltresPossiblesfield and the detailed view of the job offers inresultatsfield.filters=search_on_big_data['filtresPossibles']results=search_on_big_data['resultats']content_range=search_on_big_data['Content-Range']The number of job offers available at this point in time for this search is given by:content_range['max_results']4.1. Aggregate view of job offersThe helper functionfilters_to_dfis used to convert the fieldfiltresPossiblesin a suitable format:fromoffres_emploi.utilsimportfilters_to_dffilters_df=filters_to_df(filters)It will output:filtrevaleur_possiblenb_resultats0typeContratCDD31typeContratCDI1382typeContratLIB373experience0154experience1965experience2476experience3207qualification048qualification9769qualificationX9810natureContratE114111natureContratNS37It is then straightforward to plot these figures using the data visualization libraryseaborn:importseabornassnsg=sns.FacetGrid(filters_df,col="filtre",sharex=False,sharey=False)g=g.map(data=sns.barplot,row="valeur_possible",col="nb_resultats")4.2 Detailed view of job offersThe detailed viewresultatshas a more friendly structure and can be pass directly to apandas.DataFrameconstructor. For example, to  know the salary offered by the enterprises for this search:importpandasaspdresults_df=pd.DataFrame(results)salary_by_enterprise=(results_df[['entreprise','salaire']].dropna().agg(dict(entreprise=lambdax:x.get('nom'),salaire=lambdax:x.get('commentaire'))).dropna(subset=["salaire"]).loc[lambdadf:df.salaire.str.contains("\d+")].sort_values("salaire"))It will output:entreprisesalaire73CLEEVENSE25-45k€brutannuel112ASTEK30-40k€brutannuel113ADSERVIO30-50k€brutannuel15REDLEAN30-50k€brutannuel29EOLECONSULTING30-50k€brutannuel66PHOENIXISI32-35k€brutannuel12DGADRHCPPSDCO32-52k€brutannuel109EXPERTEAM35-45k€brutannuel47GROUPEASTEN35-48k€brutannuel16ENERGISME35-60k€brutannuel90VISEO36-50k€brutannuel80SOCIETEALTRAN,BatTeck-E.GolfPark38-42k€brutannuel14AINABLTECHNOLOGIESFRANCE38-50k€brutannuel68SOCIETEALTRAN,BatTeck-E.GolfPark40-45k€brutannuel28Katchme40-50k€brutannuel124HUMAINEA42-45k€brutannuel79SOCIETEALTRAN,BatTeck-E.GolfPark45-48k€brutannuel86DGADRHCPPFDCOApartirde34k€brutannuel114SILICOMREGIONOUESTApartirde35k€brutannuel17SNEFApartirde40k€brutannuel96NODYAGROUPApartirde40k€brutannuel89QUADRAINFORMATIQUEApartirde45k€brutannuel35HunteedApartirde49k€brutannuelNow you know where to apply.