Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WinForms, .Net Framework Новый топик    Ответить
 Выгрузка данных из web  [new]
ferzmikk
Member

Откуда:
Сообщений: 1813
Здравствуйте!

Пишу парсинг. Есть такой код на C#. В коде используется XPath.
+
using System;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using HtmlAgilityPack;
using HtmlDocument = HtmlAgilityPack.HtmlDocument;

namespace WindowsFormsApp7
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string url = "https://www.sql.ru/forum/dotnet";            

            var pageContent = LoadPage(url);
            var document = new HtmlDocument();
            document.LoadHtml(pageContent);

            //HtmlNodeCollection links = document.DocumentNode.SelectNodes("//table(class,"forumTable"));
            //foreach (HtmlNode link in links)
            // 
        }

        static string LoadPage(string url)
        {
            string result = "";
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            if (response.StatusCode == HttpStatusCode.OK)
            {
                Stream receiveStream = response.GetResponseStream();
                if (receiveStream != null)
                {
                    StreamReader readStream;
                    if (response.CharacterSet == null)
                        readStream = new StreamReader(receiveStream);
                    else
                        readStream = new StreamReader(receiveStream, Encoding.GetEncoding(response.CharacterSet));
                    result = readStream.ReadToEnd();
                    readStream.Close();
                }  
                response.Close();
            }
            return result;
        }
    }
}
В выражении document.DocumentNode.SelectNodes("..."); по разному написал. Не получается выгрузить таблицу. Как правильно написать выражение?

К сообщению приложен файл. Размер - 108Kb
12 авг 19, 13:24    [21947105]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
ferzmikk
Member

Откуда:
Сообщений: 1813
Когда перезагружаешь, то в окне контрольных значений пропадают выражения. Почему так?

К сообщению приложен файл. Размер - 25Kb
12 авг 19, 13:29    [21947112]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
Konst_One
Member

Откуда:
Сообщений: 11419
var n = document.DocumentNode.SelectNode("//*[@class='forumTable']");
12 авг 19, 13:31    [21947115]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
ferzmikk
Member

Откуда:
Сообщений: 1813
Konst_One
var n = document.DocumentNode.SelectNode("//*[@class='forumTable']");
Получилось. Спасибо!
12 авг 19, 13:49    [21947140]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
ferzmikk
Member

Откуда:
Сообщений: 1813
+class CustomDataTypes
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApp7
{
    class CustomDataTypes
    {
        public struct RowTable {
            public String Theme; //Столбец "Тема"
            public String Forum; //Столбец "Форум"
            public String Author; //Столбец "Автор"
            public String Answers; //Столбец "Ответов"
            public String Views; //Столбец "Просмотры"
            public DateTime Date; //Столбец "Дата"

            //Дополнительные поля
            public int TablePageNumber; //Номер "страницы" таблицы
        }
    }
}
+class Form1 : Form
using System;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using HtmlAgilityPack;
using HtmlDocument = HtmlAgilityPack.HtmlDocument;
using System.Collections.Generic;
using static WindowsFormsApp7.CustomDataTypes;

namespace WindowsFormsApp7
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string url = "https://www.sql.ru/forum/dotnet";           

            var pageContent = LoadPage(url);
            var document = new HtmlDocument();
            document.LoadHtml(pageContent);
            
            HtmlNodeCollection table = document.DocumentNode.SelectNodes("//*[@class='forumTable']");
            HtmlNodeCollection list_tr = table[0].SelectNodes("//tr");

            List < RowTable > list = new List<RowTable>();

            foreach (HtmlNode tr in list_tr)
            {
                RowTable rowTable = new RowTable();

                var th =tr.SelectNodes("//th");

                //rowTable.Theme =...
                //rowTable.Forum = ...
                //rowTable.Answers=...
                //rowTable.Views = ...
                //rowTable.Date = ...

                list.Add(rowTable);                
            }
            
            RowTable[] array = list.ToArray();
        }

        static string LoadPage(string url)
        {
            string result = "";
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            if (response.StatusCode == HttpStatusCode.OK)
            {
                Stream receiveStream = response.GetResponseStream();
                if (receiveStream != null)
                {
                    StreamReader readStream;
                    if (response.CharacterSet == null)
                        readStream = new StreamReader(receiveStream);
                    else
                        readStream = new StreamReader(receiveStream, Encoding.GetEncoding(response.CharacterSet));
                    result = readStream.ReadToEnd();
                    readStream.Close();
                }  
                response.Close();
            }
            return result;
        }
    }
}
Не получается получить значения строк и колонок. Акцент на выделенные строки. Как правильно написать?
13 авг 19, 16:18    [21948302]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20442
SelectNodes тебе вернет коллекцию.
Либо цикл, либо поиск в коллекции

В конце-концов, поставь точку останова, открой Immediate и экспериментируй сколько влезет
13 авг 19, 17:02    [21948379]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
ferzmikk
Member

Откуда:
Сообщений: 1813
+
            ...
            HtmlNodeCollection table = document.DocumentNode.SelectNodes("//*[@class='forumTable']");
            HtmlNodeCollection list_tr = table[0].SelectNodes("//tr");
            
            List < RowTable > list = new List<RowTable>();

            foreach (HtmlNode tr in list_tr)
            {
                RowTable rowTable = new RowTable();

                var col = tr.SelectNodes("//th");

                rowTable.Theme = col[1].InnerText;
                rowTable.Author = col[2].InnerText;
                rowTable.Answers = col[3].InnerText;
                rowTable.Views = col[4].InnerText;
                rowTable.Date = col[5].InnerText;

                list.Add(rowTable);                
            }
            ...
Пишу так, но после каждой итерации значения колонок одинаковые. Почему так?

К сообщению приложен файл. Размер - 54Kb
13 авг 19, 19:18    [21948514]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20442
ferzmikk
значения колонок одинаковые. Почему так?
Потому что ты по одной и той же коллекции елозишь
ferzmikk
"//th"


ferzmikk
В коде используется XPath.
млин, ну возьми почитай ты синтаксис xpath, вот какой смысл использовать метод тыка?
https://msiter.ru/tutorials/xpath/syntax
13 авг 19, 20:19    [21948552]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
ferzmikk
Member

Откуда:
Сообщений: 1813
Вот так получается
+С использованием цикла For
            ...
            HtmlNodeCollection rows = document.DocumentNode.SelectNodes("//*[@class='forumTable']//tr");

            List < RowTable > list = new List<RowTable>();
            
            for (int i = 1; i < rows.Count; ++i) //Обращаем внимание, что i = 1, а не 0. Исключаем заголовки
            {
                RowTable rowTable = new RowTable();

                var col = rows[i].SelectNodes("td");                

                rowTable.Theme = col[1].InnerText;
                rowTable.Author = col[2].InnerText;
                rowTable.Answers = col[3].InnerText;
                rowTable.Views = col[4].InnerText;
                rowTable.Date = col[5].InnerText;

                list.Add(rowTable);                
            }

            RowTable[] array = list.ToArray();
            ...
Выгружается.


Но если написать так
+С использованием цикла Foreach
            ...
            HtmlNodeCollection rows = document.DocumentNode.SelectNodes("//*[@class='forumTable']//tr");

            List < RowTable > list = new List<RowTable>();     


            foreach (HtmlNode row in rows)            
            {
                RowTable rowTable = new RowTable();
                
                var col = row.SelectNodes("td");

                //rowTable.Theme = col[1].InnerText;
                //rowTable.Author = col[2].InnerText;
                //rowTable.Answers = col[3].InnerText;
                //rowTable.Views = col[4].InnerText;
                //rowTable.Date = col[5].InnerText;

                list.Add(rowTable);
            }


            RowTable[] array = list.ToArray();
            ...
В выделенной строке выдает ошибку "System.NullReferenceException: "Ссылка на объект не указывает на экземпляр объекта.""

Почему так? Получатся для XPath не корректно использовать цикл foreach?
13 авг 19, 22:38    [21948672]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20442
И что, у тебя row==null в этот момент? Какая итерация цикла?
Почему при for ты пропускаешь первый элемент, при foreach не пропускаешь?
Что лежит в rows? открой в отладке, посмотри.
Что ты всякую фигню спрашиваешь до того, как попробовать самому. Тебе и так народ перестал отвечать, потому что как можно несколько лет заниматься программированием и не освоить элементарной отладки.
14 авг 19, 01:03    [21948736]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
ferzmikk
Member

Откуда:
Сообщений: 1813
Исправил

+С использованием цикла For
                for (int i = 0; i < rows.Count; ++i) 
                {
                    RowTable rowTable = new RowTable();

                    var col = rows[i].SelectNodes("td");

                    if (col == null) continue;

                    rowTable.Theme = col[1].InnerText;
                    rowTable.Author = col[2].InnerText;
                    rowTable.Answers = col[3].InnerText;
                    rowTable.Views = col[4].InnerText;
                    rowTable.Date = col[5].InnerText;
                    rowTable.TablePageNumber = NumberTablePages;

                    list.Add(rowTable);
                }
+С использованием цикла Foreach
foreach (HtmlNode row in rows)            
                {
                    RowTable rowTable = new RowTable();

                    var col = row.SelectNodes("td");

                    if (col == null) continue;

                    rowTable.Theme = col[1].InnerText;
                    rowTable.Author = col[2].InnerText;
                    rowTable.Answers = col[3].InnerText;
                    rowTable.Views = col[4].InnerText;
                    rowTable.Date = col[5].InnerText;

                    list.Add(rowTable);
                }
14 авг 19, 09:26    [21948824]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
ferzmikk
Member

Откуда:
Сообщений: 1813
1. Чтобы не забанили на сайте, где выгружаешь таблицу, разделенную на множество страниц, то актуально в коде указать заголовки. Я правильно понимаю, что достаточно указывать свойства HttpWebRequest.Accept и HttpWebRequest.UserAgent? Правильно понимаю, что значения этих свойств на разных компьютерах одинаковые?

2. Если забанят при какой то выгрузке n-ой странички таблички, то придется выгружать заново. Я правильно понимаю, что после выгрузки после n-1 странички нужно задать паузу на какое то время и продолжать выгрузку? Или между выгрузками задать паузу? Или лучше строки таблицы каждой странички лучше сохранять в отдельный файл или в базу данных? Как лучше сделать?

3. В моменте выгрузки данных по страницам, могут быть разные случаи.

Случай 1. То есть когда добавлялась строка в таблицу и в этот момент парсинг выгружает, скажем, 5-ая страницу, то получается что:
- новая строка так не попала при выгрузке первой страницы
- последняя строка на 5-й странице попадет на первую строку 6-й страницы. Получается эта строка выгрузится два раза.

Случай 2. Или наоборот удалилась строка на второй страничке таблицы. Получается что:
- первая строка 6-ой страницы перемещается в последнюю строку 5-ой страницу. И получается строка не попадает в выгрузку. А удаленная страница попала в выгрузку.

Случай 3. Или строка переместилась вверх или вниз на текущей строке, или на другую страницу.

Какие бывают решения, чтобы уловить такие логические нюансы (сдвиги)?
14 авг 19, 11:56    [21949006]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20442
1. Нет

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

3. В общем случае, когда идет интенсивная работа с этой таблицей, ты ВООБЩЕ никогда не сможешь получить актуальный срез.
Если есть возможность сортировки по дате создания записи - тут ты хотя бы не пропустишь новые записи (хотя это не застрахует от дублей, на которые надо проверять)
14 авг 19, 13:09    [21949153]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 3409
Shocker.Pro,

паузу лучше делать не константную, а переменную случайную
14 авг 19, 13:22    [21949168]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20442
Roman Mejtes
Shocker.Pro,

паузу лучше делать не константную, а переменную случайную
Не думаю, что это сильно поможет. Антиботы и антидосы, как правило, просто рассчитаны на некий порог между запросами, а случайность и так вносит сама сеть.

Но может быть еще и такой вариант, допустим пауза в одну секунду между каждым запросом устроит антибота, но 100 запросов за 100 секунд будут являться отдельной причиной для бана.
14 авг 19, 13:33    [21949193]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
ferzmikk
Member

Откуда:
Сообщений: 1813
ferzmikk
1. Чтобы не забанили на сайте, где выгружаешь таблицу, разделенную на множество страниц, то актуально в коде указать заголовки. 1.1. Я правильно понимаю, что достаточно указывать свойства HttpWebRequest.Accept и HttpWebRequest.UserAgent? 1.2. Правильно понимаю, что значения этих свойств на разных компьютерах одинаковые?
Shocker.Pro
1. Нет
Хочу уточнить на какой вопрос Вы отвечаете: 1.1. или 1.2.

Если на 1.1., то какие свойства надо указывать?

Если на 1.2., то какие значения надо задавать? Если нажать на F12 - Network - dotnet - Headers - Request Headers и оттуда берется значения Accept и User-Agent. Отсюда же брать?

Shocker.Pro
2. Могут забанить насовсем,
Если забанят на совсем, то выгружать можно только с другого компьютера. Верно?
14 авг 19, 17:18    [21949481]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20442
ferzmikk
Shocker.Pro
1. Нет
Хочу уточнить на какой вопрос Вы отвечаете: 1.1. или 1.2.
сорри, я отвечал на 1.2

Для начала прочитать, что же означают эти заголовки и на что они влияют


ferzmikk
Если забанят на совсем, то выгружать можно только с другого компьютера. Верно?
Нет. Забанят IP-адрес
14 авг 19, 18:50    [21949563]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
Dima T
Member

Откуда:
Сообщений: 13853
Shocker.Pro
Нет. Забанят IP-адрес

Может это в правила внести? Добавить в
https://www.sql.ru/forum/rules.aspx
Запрещается:
...
публикация серийных ключей, лицензий, способов взлома ПО и других методов, которые можно квалифицировать как преследуемые по закону;


PS Тупо банить по IP непрактично, практичнее накормить обращения с качающего IP говном, т.е. лить не реальную инфу, а инфу похожую на правду.
14 авг 19, 20:37    [21949618]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20442
Dima T
PS Тупо банить по IP непрактично, практичнее накормить обращения с качающего IP говном, т.е. лить не реальную инфу, а инфу похожую на правду.
1) это не типовой функционал, его придется делать специально, причем под каждый запрос - это уж совершенно непрактично.

2) а что делать людям попавшим под ложное срабатывание и накормленным этим говном? Если в случае обычного антибота человек немного поплюется, введет капчу и продолжит, а тут что делать?
Я, кстати, неоднократно и на разных сайтах, обычными действиями вызывал срабатывания антиботов. Просто быстро с помощью жестов открывал и закрывал вкладки в поисках нужной инфы
14 авг 19, 23:44    [21949695]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
ferzmikk
Member

Откуда:
Сообщений: 1813
В таблице поле "Тема" содержит само название темы и ссылку. Для того тчобы выгрузить название и ссылку, добавил строки (выделены).
+
                ...
                var pageContent = LoadPage(url);
                var document = new HtmlDocument();
                document.LoadHtml(pageContent);

                HtmlNodeCollection rows = document.DocumentNode.SelectNodes("//*[@class='forumTable']//tr");      

                foreach (HtmlNode row in rows)            
                {
                    RowTable rowTable = new RowTable();

                    HtmlNodeCollection col = row.SelectNodes("td");

                    if (col == null) continue;
                    
                    HtmlNodeCollection node = col[1].SelectNodes("a[1]/@href");

                    rowTable.Theme = node[0].InnerText;
                    rowTable.Reference = node[0].Attributes["href"].Value;
                    rowTable.Author = col[2].InnerText;
                    rowTable.Answers = col[3].InnerText;
                    rowTable.Views = col[4].InnerText;
                    rowTable.Date = col[5].InnerText;

                    list.Add(rowTable);
                 }
                    ...
Название и ссылка выгружается. Но пытался написать без использования переменной node, а использовать Col[1].
col[1].SelectNodes("a[1]/@href[@attribute='href']")
col[1].SelectNodes("a[1]/@href[1][@attribute='href']")
Возвращает null.

Как правильно написать?

К сообщению приложен файл. Размер - 51Kb
15 авг 19, 14:39    [21950139]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 5025
автор
a[1]/@href[1][@attribute='href']

Изучение XPath методом тыка. Оригинально.
15 авг 19, 17:54    [21950407]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
ferzmikk
Member

Откуда:
Сообщений: 1813
По поводу выгрузки файла с использованием классов HttpWebRequest и HttpWebResponse я правильно понимаю, что можно выгрузить только через класс FileStream? Или лучше отдельно использовать класс WebClient?
16 авг 19, 18:26    [21951349]     Ответить | Цитировать Сообщить модератору
 Re: Выгрузка данных из web  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 3409
ferzmikk
По поводу выгрузки файла с использованием классов HttpWebRequest и HttpWebResponse я правильно понимаю, что можно выгрузить только через класс FileStream? Или лучше отдельно использовать класс WebClient?

WebClient это вроде древняя версия HttpClient'а, который сейчас считается Obsolete
16 авг 19, 19:17    [21951396]     Ответить | Цитировать Сообщить модератору
Все форумы / WinForms, .Net Framework Ответить