Анализирую тесты на Одеске

После мая 2012 года, когда Одеск перестал публиковать "окономику" (www.odesk.com/oconomy), оставив только след на Веб-архиве (en), не стало единого источника информации о текущем состоянии и трендах рынка труда на этой электронной бирже труда.

Косвенную информация о числе контракторов, средней стоимости часа работ по умениям и их востребованности теперь можно получить только из тестов на Одеске. Данная информация размазана по описаниям тестов и для ее обобщения необходимо загрузить и обработать все страницы описаний. Это довольно трудоемкая и местами нудная работа, даже для питониста с requests и html5lib, называемая web scraping (en).

Извлекаем данные тестов с Scrapy

Scrapy (en) - это, написанный на Питоне, фреймворк для реализации программных роботов-пауков, извлекающих данные из веб-страниц. Реализация извлечения данных тестов Одесков со "Скрэйпи" уместилась в 3 небольших модуля:

  • items.py - содержит декларативное описание извлекаемых данных и во многом напоминает модель данных в Джанго. В нашем случае - это данные подробного описания теста на Одеске
  • tests_spider.py - реализует самого паука и содержит:
  • правила извлечения адресов страниц, которые необходимо загрузить и назначает страницам обработчиков
  • реализацию обработчиков, которые извлекают данные с помощью XPath и присваивают их объекту класса из items.py
  • settings.py - содержит настройки проекта, например, задержку между загрузкой страниц DOWNLOAD_DELAY, число одновременных запросов CONCURRENT_REQUESTS_PER_DOMAIN и другие.

Ниже приведен пример запуска процесса извлечения данных и сохранения их в CSV файл:

$ scrapy crawl -o tests_apr7.csv -t csv tests
2013-04-07 23:48:13+0400 [scrapy] INFO: Scrapy 0.16.4 started (bot: otests)
2013-04-07 23:48:13+0400 [scrapy] DEBUG: Enabled extensions: FeedExporter, LogStats, TelnetConsole, CloseSpider, WebService, CoreStats, SpiderState
2013-04-07 23:48:13+0400 [scrapy] DEBUG: Enabled downloader middlewares: HttpAuthMiddleware, DownloadTimeoutMiddleware, UserAgentMiddleware, RetryMiddleware, DefaultHeadersMiddleware, RedirectMiddleware, HttpCompressionMiddleware, ChunkedTransferMiddleware, DownloaderStats
2013-04-07 23:48:13+0400 [scrapy] DEBUG: Enabled spider middlewares: HttpErrorMiddleware, OffsiteMiddleware, RefererMiddleware, UrlLengthMiddleware, DepthMiddleware
2013-04-07 23:48:13+0400 [scrapy] DEBUG: Enabled item pipelines:
2013-04-07 23:48:13+0400 [tests] INFO: Spider opened
2013-04-07 23:48:13+0400 [tests] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2013-04-07 23:48:13+0400 [scrapy] DEBUG: Telnet console listening on 0.0.0.0:6023
2013-04-07 23:48:13+0400 [scrapy] DEBUG: Web service listening on 0.0.0.0:6080
...
2013-04-08 00:20:47+0400 [tests] INFO: Closing spider (finished)
2013-04-08 00:20:47+0400 [tests] INFO: Stored csv feed (440 items) in: tests_apr7.csv
2013-04-08 00:20:47+0400 [tests] INFO: Dumping Scrapy stats:
        {'downloader/request_bytes': 259496,
         'downloader/request_count': 888,
         'downloader/request_method_count/GET': 888,
         'downloader/response_bytes': 1672291,
         'downloader/response_count': 888,
         'downloader/response_status_count/200': 446,
         'downloader/response_status_count/301': 1,
         'downloader/response_status_count/302': 441,
         'finish_reason': 'finished',
         'finish_time': datetime.datetime(2013, 4, 7, 20, 20, 47, 939438),
         'item_scraped_count': 440,
         'log_count/DEBUG': 1334,
         'log_count/INFO': 37,
         'request_depth_max': 3,
         'response_received_count': 446,
         'scheduler/dequeued': 888,
         'scheduler/dequeued/memory': 888,
         'scheduler/enqueued': 888,
         'scheduler/enqueued/memory': 888,
         'start_time': datetime.datetime(2013, 4, 7, 19, 48, 13, 512624)}
2013-04-08 00:20:47+0400 [tests] INFO: Spider closed (finished)

Уже из этого отрывка лога видно, что на Одеске всего 440 тестов. Попробуем проанализировать полученную информацию.

Анализируем данные с Pandas

Pandas (en) - это большая библиотека для анализа данных, основанная на Numpy (en). Если Numpy называют "Матлабом на Питоне", то Pandas - это "R-язык на Питоне".

Запустим интерактивный интерпретатор Питона и загрузим сначала данные из CSV файла:

>>> import pandas as pd
>>> import numpy as np

>>> def default_value(typ, default, val):
...     try:
...         return typ(val)
...     except ValueError:
...         return default

>>> def maybe_int(val):
...     return default_value(np.int64, None, val.replace(',', ''))

>>> def maybe_float(val):
...    return default_value(np.float64, None, val)

>>> tests = pd.read_csv('tests_apr7.csv', thousands=',', converters={
...     'hourly_rate_max': maybe_float,
...     'hourly_rate_avg': maybe_float,
...     'percent_independent': maybe_float,
...     'average_qualificatinos': maybe_float,
...     'taken_test': maybe_int,
...     'passed_test': maybe_int,
...     'tests_taken': maybe_int,
... })
>>> tests
<class 'pandas.core.frame.DataFrame'>
Int64Index: 440 entries, 0 to 439
Data columns:
hourly_rate_max           432  non-null values
hourly_rate_avg           432  non-null values
percent_independent       440  non-null values
title                     440  non-null values
average_qualifications    440  non-null values
taken_test                440  non-null values
average_hours             435  non-null values
passed_test               440  non-null values
test_id                   440  non-null values
tests_taken               440  non-null values
dtypes: float64(5), int64(4), object(1)

Посмотрим подробнее на сами тесты и выделим некоторые интересные статистики.

10 тестов в порядке убывания числа контракторов

Отгадайте какой тест самый популярный.

>>> tests.sort_index(
...     by=['passed_test'], ascending=False
... ).ix[
...     :, ['test_id', 'title', 'passed_test']
... ][:10]


     test_id                                              title  passed_test
0        752  oDesk Readiness Test for Independent Contracto...       743081
439      511                     U.S. English Basic Skills Test       345213
438      688               English Spelling Test (U.S. Version)       269360
435      545                                 Office Skills Test       114577
436      584                                    Windows XP Test       104314
434      693             English Vocabulary Test (U.S. Version)        88943
437      753        oDesk Readiness Test for Agency Contractors        84282
433      506                      Email Etiquette Certification        60019
429      571                  Telephone Etiquette Certification        48861
428      484                            Call Center Skills Test        44063

10 тестов в порядке убывания средней стоимости часа

Интересная корреляция средней стоимости часа и числа контракторов прошедших тест.

>>> tests.sort_index(
...     by=['hourly_rate_avg'], ascending=False
... ).ix[
...     :, ['title', 'hourly_rate_avg', 'passed_test']
... ][:10]

                                                 title  hourly_rate_avg passed_test
14   VB.NET Programming Skills Test (Hands-on progr...            49.50           5
253                            Adobe FrameMaker 8 Test            47.75          36
131  Design Considerations for Mobile Web Applicati...            36.19          58
166                                          VLSI Test            34.00          48
143                           Checkpoint Security Test            29.00          68
248                                           RDF Test            28.50          26
240              Knowledge of ColdFusion 9 Skills Test            28.49          50
29                                     PostgreSQL Test            28.10         199
266                                  Web Services Test            27.95         301
53            Cocoa programming for Mac OS X 10.5 Test            27.55         567

10 тестов в порядке убывания суммарно отработанных часов

Показывает нижнюю оценку суммарно отработанных часов и заработанных денег на Одеске всеми контракторами на 8ое апреля, 2013 года.

>>> tests['total_hours'] = tests['passed_test'] * tests['average_hours']
>>> tests['total_earnings'] = tests['total_hours'] * tests['hourly_rate_avg']
>>> tests[tests['total_hours'] > 0].sort_index(
...     by=['total_hours'], ascending=False
... ).ix[
...     :, ['title', 'total_hours', 'total_earnings']
... ][:10]
                                                 title  total_hours  total_earnings
0    oDesk Readiness Test for Independent Contracto...    308378615    2.692145e+09
439                     U.S. English Basic Skills Test    196080984    1.815710e+09
438               English Spelling Test (U.S. Version)    144646320    9.922738e+08
435                                 Office Skills Test     70808586    4.935358e+08
436                                    Windows XP Test     61023690    5.339573e+08
434             English Vocabulary Test (U.S. Version)     52120598    3.841288e+08
437        oDesk Readiness Test for Agency Contractors     49642098    2.765065e+08
433                      Email Etiquette Certification     44474079    3.740270e+08
429                  Telephone Etiquette Certification     36499167    2.901684e+08
428                            Call Center Skills Test     33884447    2.232985e+08

Comments !

blogroll

social