Как парсить сайты с авторизацией?

144
30 июня 2019, 18:00

Парсер с использованием Anglesharp.

Как парсить сайты с авторизацией?
Я пробую написать парсер.
Если я правильно понял теорию, то логика должна быть следующая:
- авторизация;
- получить куки;
Движение по страницам
- отправить куки;
- перейти на страницу_1;
- отправить куки;
- перейти на страницу_2;

Форма авторизации

<form name="login" class="ui large form" action="/login/" method="POST">
    <div class="required field ui grid aligned left"><input name="login[login]" value="" type="text" placeholder="Электронная почта" maxlength="64" autocomplete="off"></div>
    <div class="required field ui grid aligned left">
        <input name="login[password]" value="" type="password" maxlength="32" autocomplete="off" placeholder="Пароль">
    </div>
    <div class="equal width fields" style="flex-wrap:nowrap;">
        <div class="field" style="text-align: left;">
            <div class="ui checkbox large step">
                <input id="remember" type="checkbox" name="login[remember]" tabindex="0" value="1" class="hidden">
                <label for="remember">Запомнить меня</label>
            </div>
        </div>
        <div class="field" style="text-align: right;">
            <a href="/forgot/">Забыли пароль?</a>
        </div>
    </div>
    <div class="field">
        <button class="fluid positive ui button big">Войти</button>
    </div>
    <input name="login[type]" type="hidden"><input name="login[init]" type="hidden" value="">
</form>

Минимальный код

public async void Authorization(string pathPageLogin, string userName, string password)
{
    IConfiguration config = Configuration.Default.WithDefaultLoader().WithCookies();
    IBrowsingContext browsingContext = BrowsingContext.New(config);
    browsingContext.OpenAsync(pathPageLogin).Wait();

    (browsingContext.Active.QuerySelector("input[name = 'login[login]']") as IHtmlInputElement).Value = userName;
    (browsingContext.Active.QuerySelector("input[name = 'login[password]']") as IHtmlInputElement).Value = password;
    (browsingContext.Active.QuerySelector("form") as IHtmlFormElement).SubmitAsync().Wait();

}
public async void Parsing(string url, string pathFileHtml)
{
    HttpClient client = new HttpClient();
    var response = await client.GetAsync(url); // скачиваем страницу
    string source = await response.Content.ReadAsStringAsync(); // Переносим в переменную
    #region Сохранить страницу в файл
    File.WriteAllText(pathFileHtml, source);
    #endregion Сохранить страницу в файл
    #region Парсер
    // HTML парсер, который доступен из "AngleSharp".
    var domParser = new HtmlParser();
    // Спарсим асинхронно наш исходный код и получим документ с которым мы можем работать
     var document = await domParser.ParseAsync(source);
    // *** Парсер ****              
    // результат
    var list = new List<string>();
    var items = document.QuerySelectorAll("a").Where(item =>
                item.ClassName != null && item.ClassName.Contains("post__title_link"));
    foreach (var item in items)
    {
        list.Add(item.TextContent);
    }
    #endregion
}

Вопросы.
1. Правильно ли я понимаю логику?
2. Как сделать код с минимальным набором основных методов для простых сайтов, чтобы было видно принцип логики?

Дополнение
Для примера использовать: rabota.by/login/

Дополнение
Логин - test9631@yandex.by
Пароль - Ym3LDp1FPs

Дополнение

Answer 1

Анализируем.

Первым делом надо проанализировать сайт и понять как он работает. Я лично буду использовать Fiddler для отлова запросов, вы это можете делать там, где вам удобно...

И так, заходим на страницу авторизации, включаем отлов запросов, авторизуемся и смотрим на запросы.
Обычно они выглядят довольно заметно и идут на страницу вида /login или что то в этом духе.

После авторизации на сайте я поймал такой запрос:

Смотрим сам запрос:

POST /login/ HTTP/1.1
Host: rabota.by
Connection: keep-alive
Content-Length: 186
Cache-Control: max-age=0
Origin: https://rabota.by
Upgrade-Insecure-Requests: 1
DNT: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 Vivaldi/2.2.1388.37
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: https://rabota.by/
Accept-Encoding: gzip, deflate, br
Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: sessionRabota=4t8r5v068lb7g9alo3; _ga=GA1.2.20569718.1545649; _gid=GA1.2.202925.15449; _ym_uid=15595112; _ym_d=154552; _ym_isad=1; _ym_visorc_2318=w; 388c2c03bbed9f4661; captcha=4509285; captcha_md5=59bf907333254603af10; arp_scroll_position=0; *0=*0
  • Первым делом нас тут интересует тип запроса, у нас это POST на адрес /login/.
  • Далее смотрим на тип передаваемых данных Content-Type: application/x-www-form-urlencoded.
  • Также может пригодиться User-Agent и некоторые Cookie.

Так, как у нас запрос с данными веб формы, то также стоит посмотреть его тело:

login[login]    user@mail.com
login[password] pass
login[remember] 1
submitButton    Войти
login[type] cad5afb6ed280bc4041d5689d561144a

Здесь все довольно понятно - наши логин, пароль, запоминать или нет, имя кнопки и неизвестный параметр с логина. Проверим этот неизвестный параметр, просто проделав авторизацию еще раз. Если он изменится, то стоит искать как он формируется, если нет, то можно использовать его. В моем случае он статичный.

Ну и еще стоит посмотреть сам ответ сервера, что он отдает и что он устанавливает:

Content-Type: text/html; charset=UTF-8
Set-Cookie: *0=%2A0; expires=Wed, 12-Dec-2018 19:21:31 GMT; Max-Age=-864000; path=/; domain=rabota.by
Set-Cookie: 666c9aea5601eb92b8=7df1b7318a82be0b068b; expires=Tue, 22-Jan-2019 19:21:32 GMT; Max-Age=2678400; path=/; httponly
Set-Cookie: d2c3f55839194555558=f33b13af8cfcd2d14c8650; expires=Tue, 22-Jan-2019 19:21:32 GMT; Max-Age=2678400; path=/; httponly

Видно, что в ответ сервер отдает нам обычный html и устанавливает пару Cookie. Тело ответа смотреть пока бессмысленно.

Пробуем отправить запрос сами.

Для этих целей отлично подходит Postman. Устанавливаем, пропускаем авторизацию (или нет) и создаем новый запрос.

  • Выбираем POST.
  • Указываем адрес запроса https://rabota.by/login
  • [вкладка Body] Указываем тип данных x-www-form-urlencoded
  • [вкладка Body] Заполняем все поля запроса
  • Пробуем отправить запрос.
  • Смотрим данные (HTML). И видим там, что простой отправки данных нам не достаточно, сайт не авторизует нас. Что то не хватает. Обычно это либо заголовок UserAgent или какой то уникальный, либо Cookie.
  • Пробуем добавить UserAgent - не подошел.
  • Пробуем подобрать Cookie - и тут видим, что сайт наконец нас пустил (в HTML видим свои данные).

Теперь очистим запрос:

  • Удаляем из Cookie по одному, пока не перестанет отправлять нам нужные данные. Я лично выяснил, что нужны всего одна Cookie - *0=*0.
  • [вкладка Body] Тут по такому же принципу, убираем все не нужное, убирая просто галки. Мои наблюдения показывают, что достаточно всего лишь login[login], login[password] и login[type].
  • [вкладка Headers] Убираем также лишние заголовки. На авторизацию влияют Content-Type и Referer.

READ ALSO
Не работает условие (Unity)

Не работает условие (Unity)

Почему не работает условие?

116
Шанс выпадения числа в Random.Range

Шанс выпадения числа в Random.Range

Как сделать чтобы можно было установить шанс выпадения числа в процентах

107
Как получить доступ к MainWindow viewmodel из Page

Как получить доступ к MainWindow viewmodel из Page

Пытаюсь разобраться с WPFВ моем примере мне нужно получить доступ к MainWindow viewmodel из Page в XAML

116
WPF. MVVM. Как сохранить состояние Checked массива toggleButton

WPF. MVVM. Как сохранить состояние Checked массива toggleButton

Есть коллекция radiobutton, по нажатии на каждую такую кнопку формируется коллекция togglebuttonДанные для формирования и того и другого списка берутся...

145