RkBlog

Hardware, programming and astronomy tutorials and reviews.

Problem z ofertami pracy w sieci

Bazując m.in. na swoich doświadczeniach - jest masa serwisów oferujących oferty pracy. Jedne bardziej renomowane, inne "darmowe" i zawierające wiele słabych ofert. Są też "franczyzy" - oferty pracy z jednego serwisu udostępniane w drugim, czy też dodaw

Bazując m.in. na swoich doświadczeniach - jest masa serwisów oferujących oferty pracy. Jedne bardziej renomowane, inne "darmowe" i zawierające wiele słabych ofert. Są też "franczyzy" - oferty pracy z jednego serwisu udostępniane w drugim, czy też dodawanie tej samej oferty przez firmę na wielu stronach. Nie ma też chyba konkretnego użytecznego serwisu (poza Google) z prawdziwego zdarzenia będącego wyszukiwarką ofert z większości/wszystkich liczących się serwisów ofertowych (Jest np. praca.money.pl, ale to element większego serwisu i nie promuje się ostro jako multikatalog ofert pracy). Generalnie zamieszczanie ofert jest płatne, więc jeżeli szukamy dobrych ofert - musimy przejrzeć wszystkie fajne serwisy żeby mieć pewność że sprawdziliśmy wszystkie fajne oferty.

Od strony Django jakby taki serwis, zbieracz ofert pracy mógł wyglądać? Najprostsze rozwiązanie to pełnotekstowa wyszukiwarka indeksująca oferty pracy. Konkurencja dla Google, lecz jeżeli zaoferuje trafniejsze wyszukiwanie (np. z filtrowaniem po branży, województwie czy mieście) to będzie poręczniejszy. Xapian, Whoosh, czy może na całego i Solr? Druga opcja to pobieranie (indeksowanie) ofert pracy, wyciąganie ich treści, dodatkowych danych i zapis we własnej bazie danych. W efekcie otrzymamy serwis podobny do innych ofertowych serwisów, lecz oferujący przegląd ofert z wielu źródeł. Kwestia to napisanie parserów dla każdego serwisu - listę najnowszych ofert zazwyczaj otrzymamy z RSS, do tego trochę regexów do wyciągnięcia treści ogłoszenia z gotowej strony, jak i dla każdego źródła będzie pewnie konieczne trochę poprawek różnego typu (CSS, w parserze), żeby treść importowała się w miarę poprawnie - chyba że i treść ogłoszenia rozbijemy na poszczególne składowe pozbywając się formatowania HTML źródła. W przypadku większych serwisów można by pewnie uzyskać dostęp do API umożliwiającego bezproblemowy import ofert.

Dla przykładu dość prosty parser:

# -*- coding: utf-8 -*-
from datetime import datetime
import sys
from os import environ
import urllib2
from re import findall

environ['DJANGO_SETTINGS_MODULE'] = 'settings'

import feedparser

from settings import *
from django.contrib.sessions.models import *
# proof-of-concept app
from diamandas.jobmaster.models import *

############
## Jobexpress
############
source = JobSource.objects.get(title='Jobexpress')
## IT

data = feedparser.parse('http://www.jobexpress.pl/recent,it,84.html')
if data and 'entries' in data:
	for elem in data['entries']:
		sum = elem['summary_detail']
		published = sum['value'].split(',')[0].strip().split('-')
		published = datetime(int(published[2]), int(published[1]), int(published[0]))
		company = sum['value'].split(',')[1].strip()
		
		opener = urllib2.build_opener()
		opener.addheaders = [('user-agent', 'Opera/9.64 (X11; Linux x86_64; U; en) Presto/2.1.1'), ('referer', 'http://www.jobexpress.pl/recent,it,84.html')]
		o = opener.open(elem['link'])
		of = o.read()
		text = findall(r'(?xs)<ul\s*class="oferta_pracy">(.*?)<!--\s*eof:\s*oferta''', str(of))
		if text and len(text) > 0:
			text = text[0]
			# cleaning
			text = '<ul>' + text
			text = text.replace('href="', 'href="http://www.jobexpress.pl/')
			text = text.replace('src="', 'src="http://www.jobexpress.pl/')
			
			city = findall(r'(?xs)<span\s*class="cv_label">Miejsce\s*pracy:\s*</span>(.*?)</li>''', text)
			try:
				city = city[0].strip()
			except:
				city = '???'
			
			# TODO
			region = 'Na bazie miasta'
			
			branch = 'Informatyka/Programowanie'
			try:
				j = JobOffer.objects.get(position=elem['title'], company=company, city=city)
			except:
				j = JobOffer(position=elem['title'], company=company, source=source, url=elem['link'], indexed_at=datetime.now(), updated_at=datetime.now(),
						published_on_source=published, city=city, region=region, branch=branch, offer=text)
				j.save()
			
				print u'ZAPISANO: %s' % elem['title']
			else:
				j.updated_at = datetime.now()
				j.offer=text
				j.save()
				print u'ZAKTUALIZOWANO: %s' % elem['title']
			
A modele mogą wyglądać np. tak:
class JobSource(models.Model):
	"""
	Keeps a "list" of sites with job offers that are parsed by the application.
	Just for ease of data manipulation
	"""
	title = models.CharField(verbose_name='Tytuł', max_length=255)
	url = models.CharField(verbose_name='URL Strony głównej', max_length=255)
	css = models.TextField(verbose_name='Style CSS', blank=True)
	class Meta:
		verbose_name = 'Serwis z ofertami'
		verbose_name_plural = 'Serwisy z ofertami'
	def __str__(self):
		return self.title
	def __unicode__(self):
		return self.title

class JobOffer(models.Model):
	"""
	Indexed job offers from various sites
	"""
	position = models.CharField(verbose_name='Stanowisko', max_length=255)
	company = models.CharField(verbose_name='Firma', max_length=255)
	source = models.ForeignKey(JobSource, verbose_name='Źródło')
	url = models.CharField(verbose_name='URL oferty', max_length=255)
	indexed_at = models.DateTimeField(verbose_name='Data zaindeksowania oferty')
	updated_at = models.DateTimeField(blank=True, null=True, verbose_name='Data ostatniej aktualizacji')
	published_on_source = models.DateTimeField(blank=True, null=True, verbose_name='Data publikacji na stronie-źródle')
	is_inactive = models.BooleanField(blank=True, default=False, verbose_name='Oferta nieaktywna')
	city = models.CharField(verbose_name='Miasto', max_length=255)
	region = models.CharField(verbose_name='Województwo', max_length=255)
	branch = models.CharField(verbose_name='Branża', max_length=255)
	offer = models.TextField(verbose_name='Treść oferty')
	class Meta:
		verbose_name = 'Oferta'
		verbose_name_plural = 'Oferty'
	def __str__(self):
		return self.position
	def __unicode__(self):
		return self.position
Powyższy przykład jest dość prosty i sporo można rozbudować ten pomysł (jak i wyciągać rozbite dane, a nie zbitą treść oferty). Ale w efekcie można wyświetlić ogłoszenie u siebie (choć aplikowanie zazwyczaj wymaga przejścia na źródłowy serwis):
jobmaster
Normalny serwis z dobrą marką zarabia na publikacji ogłoszeń, a tego typu serwis mógłby zarabiać np. poprzez dodatkowe usługi sprzedawane indeksowanym serwisom (np. własny szablon, wyróżnianie ofert), jak i też standardowo na reklamach kontekstowych. Ważne żeby indeks był kompletny i łatwo dostępny. Czy jest miejsce dla dobrze napisanego serwisu tego typu? Myślę że tak... jakieś komentarze? :)

RkBlog

2 July 2009;

Comment article