Форум программистов, компьютерный форум, киберфорум
Наши страницы
C# .NET
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 1, средняя оценка - 4.00
yukoz
4 / 4 / 2
Регистрация: 14.03.2014
Сообщений: 45
#1

Авто-обновление резюме на хэдхантере - C#

10.09.2014, 18:14. Просмотров 2619. Ответов 22
Метки нет (Все метки)

Привет всем!

Изредка ищу новых заказчиков на хэдхантере, задался идеей написать небольшую программу по авто-обновлению своего резюме (каждые 4 часа). Но что-то никак не выходит... Выдает на GetResponse() - ошибка 500... может кто подскажет куда капать?

Делаю так:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
string Url = "http://hh.ru/applicant/resumes/touch";
            string Data = "resume:ee07_код_моего_резюме_a339ff00cbaf0b0039e&undirectable:true";
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(Url);
            req.Method = "POST";
            req.Timeout = 100000;
            req.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
            req.Referer = "http://hh.ru/applicant/resumes/view?resume=ee07a33_код_моего_резюме_74471754438";
 
            CookieContainer cookies = new CookieContainer();
            req.CookieContainer = cookies;
            Cookie cookieReg = new Cookie("hhtoken", "5VLgvBiB0_мой_токен__Vyflnel", "", "hh.ru");
            req.CookieContainer.Add(cookieReg);
            Cookie cookieReg2 = new Cookie("hhuid", "hA!Ha_мой_уид_VEPVH4uRA--", "", "hh.ru");
            req.CookieContainer.Add(cookieReg2);
 
            byte[] sentData = Encoding.ASCII.GetBytes(Data);
            req.ContentLength = sentData.Length;
            req.GetRequestStream().Write(sentData, 0, sentData.Length);
 
            req.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0";
            req.Accept = "text/plain, */*; q=0.01";
 
            WebResponse res = req.GetResponse();
Данные для куков нашел через Firefox.

Вот что анализ трафика говорит (см. вложение).
0
Миниатюры
Авто-обновление резюме на хэдхантере  
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
10.09.2014, 18:14
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Авто-обновление резюме на хэдхантере (C#):

Авто обновление больших приложений
Добрый день, вопрос такой. Необходимо сделать авто обновление приложения. Если...

авто обновление страниц
в моем мальноков примере есть проблема: когда пользователь ввел данные на...

Авто обновление программы
Допустим я с помощью get запроса получил ссылку с хостинга,как мне её скачать и...

Авто обновление браузера
Есть браузер Yandex (можно Chrome и IE). Подскажите пожалуйста как сделать...

Реализация авто-обновление блока
Поскажите пожалуйста реализацию, как автоматически обновлять блок, когда в базе...

Авто обновление собственного браузера
Вот есть программа у меня, которая обновляет открытую страницу открытого...

22
kolorotur
Эксперт .NET
9937 / 8323 / 2044
Регистрация: 17.09.2011
Сообщений: 14,332
10.09.2014, 21:26 #2
Цитата Сообщение от yukoz Посмотреть сообщение
авто-обновлению своего резюме (каждые 4 часа).
Бодро у вас резюме обновляется!
Это такая частота смены места работы?
0
yukoz
4 / 4 / 2
Регистрация: 14.03.2014
Сообщений: 45
11.09.2014, 17:35  [ТС] #3
Лучший ответ Сообщение было отмечено kolorotur как решение

Решение

Цитата Сообщение от kolorotur Посмотреть сообщение
Бодро у вас резюме обновляется!
Это такая частота смены места работы?
Частота не большая, просто hh позволяет обновлять свое резюме раз в 4 часа, чтобы оно было в первых результатах поиска у работодателей, больше предложений будет - больше выбор... В инете на хабре нашел, один делал на дэлфях подобное, причем не так давно, и вроде как у него все получилось, а у меня что-то никак, постоянная ошибка 500 (ответ сервера), может что-то не так делаю?

Добавлено через 6 часов 40 минут
Я понял почему возникает ошибка 500, потому что в заголовках POST запроса обязательно должен быть параметр "X-Xsrftoken", только как его туда воткнуть, пытался сделать так:

C#
1
req.Headers.Add("X-Xsrftoken", "067d9e4c41607ebc505");
Не получается В анализе трафика этот заголовок не появляется...

Добавлено через 11 минут
Всё, победил, ошибки 500 нет - УРА!

C#
1
2
3
WebHeaderCollection hd = new WebHeaderCollection();
            req.Headers = hd;
            req.Headers.Add("X-Xsrftoken", "067d9e4c07ebc505");
2
Dronello
0 / 0 / 0
Регистрация: 28.09.2014
Сообщений: 6
28.09.2014, 17:34 #4
а как получить значение X-Xsrftoken ?

у меня тоже ошибка 500 выскакивает (
0
yukoz
4 / 4 / 2
Регистрация: 14.03.2014
Сообщений: 45
28.09.2014, 21:05  [ТС] #5
Цитата Сообщение от Dronello Посмотреть сообщение
а как получить значение X-Xsrftoken ?
у меня тоже ошибка 500 выскакивает (
Очень просто - через веб-консоль Firefox'a, в разделе - заголовки.
2
Dronello
0 / 0 / 0
Регистрация: 28.09.2014
Сообщений: 6
28.09.2014, 22:36 #6
чуть чуть неверно - X-Xsrftoken должна быть равна значению скрытой переменной "_xsrf" , которая появляется на форме логина, в html такое искать и парсить

<input type="hidden" name="_xsrf" value="024e845f8e4e469ebd6eee5f2d7375f0">

а так - ход ваших мыслей ОЧЕНЬ верный оказался -без этого заголовка - ошибка 500 , с этим заголовком при досрочном обновлении - 409 ошибка - все верно
0
z668
27 / 27 / 5
Регистрация: 24.03.2013
Сообщений: 239
29.09.2014, 01:02 #7
Ребят, я все понимаю конечно, но зачем вам лишние проблемы с get и post запросами? В любой момент hh может поменять эти значения. Проще (да и надежнее) использовать WebBrowser. Тем более не в многопоточном режиме софт работать будет.
0
Dronello
0 / 0 / 0
Регистрация: 28.09.2014
Сообщений: 6
29.09.2014, 02:09 #8
да я вообще через php и curl делаю - я случайно в ветку залез - за идеей ))
0
Saymsik
0 / 0 / 0
Регистрация: 14.10.2014
Сообщений: 2
14.10.2014, 15:29 #9
Dronello,
А можно поподробнее, каким образом у вас выглядит запрос?
Спасибо!
0
Dronello
0 / 0 / 0
Регистрация: 28.09.2014
Сообщений: 6
14.10.2014, 16:51 #10
обычный curl - из хитростей надо в заголовок добавить X-Xsrftoken

его его значение парсится из input c атрибутом name=_xsrf

массив POST состоит из 2 элементов (resume - id вашего резюме и undirectable=true)

без заголовка будет 500 ошибка, с ним - 200 или 409 - если нельзя обновить
0
Saymsik
0 / 0 / 0
Регистрация: 14.10.2014
Сообщений: 2
14.10.2014, 19:47 #11
Dronello, а пример можно?
0
Dronello
0 / 0 / 0
Регистрация: 28.09.2014
Сообщений: 6
14.10.2014, 21:54 #12
а что непонятно в каком месте? вроде старался все подводные камни объяснить - на каком месте стопор то ???
0
joub
1 / 1 / 4
Регистрация: 08.01.2013
Сообщений: 135
29.12.2014, 11:57 #13
и я в тему добавлять...
X-Xsrftoken - в куках проскакивает в капсе - и это была мая ошибка... требует именно строчные буквы...
0
Psilon
Master of Orion
Эксперт .NET
5981 / 4834 / 901
Регистрация: 10.07.2011
Сообщений: 14,439
Записей в блоге: 5
Завершенные тесты: 4
29.12.2014, 15:52 #14
z668, если что-то поменяется, то веббраузер не спасет, а прямой запрос позволяет лучше всё контролировать/меньше жрет памяти проца/в целом изящнее.
0
joub
1 / 1 / 4
Регистрация: 08.01.2013
Сообщений: 135
29.12.2014, 16:17 #15
А еще можно автоматизировать. Имея 2-3 резюме, через cron запускать сервисную программу которая: авторизуется, найдет все резюме, up-нет их - и это каждые 4 часа... ))

Вот только один вопрос меня интересует, как точно на стороне hh идет просчет времени - ровно 4.00 часа и не секундой больше?

Добавлено через 18 минут
А кто нибудь получал вот такое?

405: Method Not Allowed
0
sergsa
0 / 0 / 0
Регистрация: 29.11.2016
Сообщений: 4
18.10.2017, 11:43 #16
Тоже 405 ошибка...

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
 
namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            string Url = "http://hh.ru/applicant/resumes/touch";
            string Data = "resume:b8c7d90fff02ece6911139ed1f646f57616d4a&undirectable:true";
            WebHeaderCollection hd = new WebHeaderCollection();
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(Url);
            req.Method = "POST";
            req.Headers = hd;
            req.Headers.Add("X-Xsrftoken", "2c8e14cca2940111e1b1116c52fe0721");
            req.Headers.Add("X-Requested-With", "XMLHttpRequest");
            req.Timeout = 100000;
            req.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
            req.Referer = "https://hh.ru/resume/b8c7d90fff02ece6911139ed1f646f57616d4a";
 
            CookieContainer cookies = new CookieContainer();
            req.CookieContainer = cookies;
            Cookie cookieReg = new Cookie("hhtoken", "olbQY_AYjq_BggghP4NXLs5m7A_o", "", "hh.ru");
            req.CookieContainer.Add(cookieReg);
            Cookie cookieReg2 = new Cookie("hhuid", "fP1rFMcddfJRCFnloIE3tQ--", "", "hh.ru");
            req.CookieContainer.Add(cookieReg2);
 
            byte[] sentData = Encoding.ASCII.GetBytes(Data);
            req.ContentLength = sentData.Length;
            req.GetRequestStream().Write(sentData, 0, sentData.Length);
 
            req.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0";
            req.Accept = "*/*";
 
            WebResponse res = req.GetResponse();
        }
    }
}
Fiddler выдает такое:
POST [url]https://hh.ru/applicant/resumes/touch[/url] HTTP/1.1
Accept: */*
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Xsrftoken: 2c8e14cca2940111e1b1116c52fe0721
X-Requested-With: XMLHttpRequest
Referer: [url]https://hh.ru/resume/b8c7d90fff02ece6911139ed1f646f57616d4a[/url]
Accept-Language: ru-RU
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: hh.ru
Content-Length: 63
DNT: 1
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: _xsrf=2c8e14cca2940b1111b7716c52fe0721; regions=1; hhrole=applicant; unique_banner_user=1508221057.622340413314888; GMT=3; _ga=GA1.1.1504221742.1508221060; _gid=GA1.1.179902565.1508221060; _ym_uid=15082211101061245402; _ym_isad=2; _ym_visorc_156828=w; tmr_detect=0%7C1508225034217; display=desktop; hhtoken=olbQY_AYjq_BggghP4NXLs5m7A_o; hhuid=fP1rFMcddfJRCFnloIE3tQ--; crypted_id=6430B60D2C3C58BF271A8D9A3A5471C6F722104504734B32F0D03E9F8; region_clarified=hh.ru; redirect_host=hh.ru; last_visit=1508214231076::1508225031076

resume=b8c7d90fff02ece6911139ed1f646f57616d4a&undirectable=true

Есть идеи?

Добавлено через 21 час 17 минут
В общем разобрался.
ошибка 405 неправильный метод возникает потому, что урл должен быть https, а не http
в дальнейшем появляется ошибка 400 не правильный запрос потому, что в самом запросе должны быть знаки = вместо :
0
_exp10der_
Warrior
490 / 417 / 177
Регистрация: 23.11.2014
Сообщений: 932
18.10.2017, 21:38 #17
Когда то давно делал когда искал работу, вот скорее всего должно работать

1)Sign in https://dev.hh.ru/admin
2)Click Request a token.
3)Open file Config.json
4)Insert AccessToken from step 2,
5)Insert ResumeId https://spb.hh.ru/applicant/resumes

Config.json
JSON
1
2
3
4
{
  "ResumeId": "put it here",
  "AccessToken": "put it here"
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
namespace HeadHunter_API
{
    using System;
    using System.IO;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Threading.Tasks;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
 
    internal class Program
    {
        private static readonly Action<string> Log = Console.WriteLine;
        private static void Main() => MainAsync().GetAwaiter().GetResult();
 
        private static async Task MainAsync()
        {
            var config = JsonConvert.DeserializeObject<Config>(File.ReadAllText("Config.json"));
 
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("https://api.hh.ru");
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
                    config.AccessToken);
                client.DefaultRequestHeaders.UserAgent.ParseAdd(
                    "Exp10der Resume Prolongation/1.0 (konstantin.writing.code@gmail.com)");
 
                var content = await client.GetStringAsync($"/resumes/{config.ResumeId}/");
 
                var nextPublishAt = JObject.Parse(content)["next_publish_at"].ToObject<DateTime>();
 
                Log($"Time to update the resume: {nextPublishAt}");
 
                // Trying to update resume
                var updateResponse =
                    await client.PostAsync($"/resumes/{config.ResumeId}/publish", new StringContent(""));
 
                var contents = await updateResponse.Content.ReadAsStringAsync();
 
                Log($"Update Response: {contents}");
            }
        }
    }
}
для работы json нужно поставить либину PM> Install-Package Newtonsoft.Json -Version 10.0.3
https://www.nuget.org/packages/Newtonsoft.Json/
1
big_mc
0 / 0 / 0
Регистрация: 05.08.2015
Сообщений: 3
14.03.2018, 21:31 #18
Я полгода назад сайт сделал, автоматически обновляющий через их API резюме любого желающего, бесплатно.
Правда, письмо пришло, что скоро это самое API у них будет платным, увы.
Но пока всё работает

hhupdate dot ru
P.S. если считается рекламой, то прошу меня простить) и удалить этот пост
0
joub
1 / 1 / 4
Регистрация: 08.01.2013
Сообщений: 135
14.03.2018, 21:34 #19
мы же на cyberforum, тут интересен алгоритм решения или код решающий задачу, а ни как не сторонние-закрытые сервисы.
0
big_mc
0 / 0 / 0
Регистрация: 05.08.2015
Сообщений: 3
14.03.2018, 22:59 #20
Цитата Сообщение от joub Посмотреть сообщение
мы же на cyberforum, тут интересен алгоритм решения или код решающий задачу, а ни как не сторонние-закрытые сервисы.
согласен! я, правда, на питоне написал)
из ингредиентов основные, это Flask и Celery

1)зарегистрировал приложение в админке хх, получил ключи
2)ознакомился с их API и OAuth2 в целом
3)написал модельки пользователей и задач c Flask, авторизацию пользователя с его токенами от хх
4)шаблоны на Bootstrap4 наклепал
5)написал периодическую задачу с Celery, которая обновляет все включенные резюме тем же /resumes/<ID>/publish, только подставляя в заголовки access-токены пользователей
6)ну конфиги-логи и так понятно

возможно что-то упустил
0
14.03.2018, 22:59
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.03.2018, 22:59
Привет! Вот еще темы с решениями:

Авто обновление данных в Excel
Здравствуйте! Подскажите пожалуйста каким образом можно сделать авто...

Авто обновление div Блока
Здравствуйте. У меня например есть div блок, текст в котором должен...

Не работает авто обновление виндовс
Проблема такая, у меня не работает авто обновление виндовс, а если зайти в...

Описать базовый класс автомобиль и от него наследуются классы: грузовые авто, уборочные авто, спортивные авто
Всем привет!:) хочу спросить кто нибудь писал программы с наследованием на...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru