Парсинг HTML в iOS приложении

23 Янв
2012

Добрый день, уважаемые блога-юзеры.

Сегодня на github я наткнулся на отличный HTML-парсер, коотрый смогут освоить даже новички в программировании под iOS.

Под блогакатом я расскажу вам, что это такое и с чем его едят.

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

Подготовка

  • Перенесите *.h и *.m файлы парсера в ваш проект
  • В настройках добавьте «/usr/include/libxml2» в поле «header search paths»
  • Добавьте фреймворк libxml2.dylib


Получаем HTML код

В качестве примера мы будем использовать мобильную версию хабра, для этого с помощью ASIHTTPRequest отправим запрос по адресу m.habr.ru/?fl и получим требуемый нам html код.

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

Наконец-то парсим

Код мобильной странички Блога выглядит примерно так:
...
<body>

<div class="tm"><a href="http://m.habrahabr.ru/" accesskey="2">μHabr</a></div>
<div class="c">
<ul class="tl">

<li>
<h3><a href="http://m.habrahabr.ru/post/136556/" class="t">Один дизайн или много?</a> ← <a href="http://m.habrahabr.ru/blog/web_design/">Веб-дизайн</a></h3>
<span><em>Exitmusic, вчера в 02:36</em> <a href="http://m.habrahabr.ru/post/136556/" class="comments">комментарии</a> (8)</span>
</li>

<li>
<h3><a href="http://m.habrahabr.ru/post/136517/" class="t">Что такое ITSM?</a> ← <a href="http://m.habrahabr.ru/blog/sysan4dummies/">Анализ и проектирование систем</a></h3>
<span><em>vvl, вчера в 11:55</em> <a href="http://m.habrahabr.ru/post/136517/" class="comments">комментарии</a> (3)</span>
</li>
</body>
...


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

Для начала получим код, который находится в «body» нашей странички (не забудьте импортировать оба *.h файла парсера):

NSError *error = nil;
    HTMLParser *parser = [[HTMLParser alloc] initWithString:html error:&error];
    
    if (error) {
        NSLog(@"Error: %@", error);
        return;
    }
    
    HTMLNode *bodyNode = [parser body];


Я думаю, вы уже заметили, что информация о каждом посте находится между тэгами «li». Следовательно, мы должны выделить эти участки html-кода, чтобы продолжить обработку. Сказано — сделано:
NSArray *postNodes = [bodyNode findChildTags:@"li"];


Я думаю, что проще всего будет собрать всю информацию о постах в NSMutableDictionary, чтобы в последствии мы могли легко с ней работать. Для этого инициализируем этот объект:
NSMutableArray *articlesDone = [[NSMutableArray alloc] init];


Анализируем код дальше и видим, что в блоке с каждым постом есть два элемента с тэгом «a». Первый — название поста, второй — название блога. Отсюда мы можем получить большую часть нужных нам данных: название поста, блога и ссылки на них. Это исполнит следующий код:

for (HTMLNode *postNode in postNodes) {
        NSMutableDictionary *article = [[NSMutableDictionary alloc] init];
        NSArray *aTags = [postNode findChildTags:@"a"];
        if (aTags.count > 0) {
            HTMLNode *aOne = [aTags objectAtIndex:0];
            NSString *nameOfArticle = [aOne contents];
            NSString *link = [aOne getAttributeNamed:@"href"];
            [article setObject:nameOfArticle forKey:@"title"];
            [article setObject:link forKey:@"link"];
            HTMLNode *aTwo = [aTags objectAtIndex:1];
            NSString *blogname = [aTwo contents];
            NSString *blogLink = [aTwo getAttributeNamed:@"href"];
            [article setObject:blogLink forKey:@"bloglink"];
            [article setObject:blogname forKey:@"blog"];
            [articlesDone addObject:article];
        }
    }


Итак, мы получили большую часть информации о посте, осталось только получить имя автора, но это оказалось более сложной задачей, ведь имя автора соединено с датой, поэтому нам понадобится использовать NSScanner, ведь ник отделен запятой. Итак, немного модифицируем нынешний код, чтобы получить недостающую информацию. В результате получаем:
 for (HTMLNode *postNode in postNodes) {
        NSMutableDictionary *article = [[NSMutableDictionary alloc] init];
        NSArray *titles = [postNode findChildTags:@"a"];
        if (titles.count > 0) {
            HTMLNode *aOne = [titles objectAtIndex:0];
            NSString *nameOfArticle = [titleOne contents];
            NSString *link = [titleOne getAttributeNamed:@"href"];
            HTMLNode *authorNode = [postNode findChildTag:@"em"];
            NSString *authorAndDate = [authorNode contents];
            NSScanner *scanner = [[NSScanner alloc] initWithString:authorAndDate];
            [scanner scanUpToString:@"," intoString:nil];
            NSString *author = [authorAndDate substringWithRange:NSMakeRange(0, scanner.scanLocation)];
            [scanner release];
            HTMLNode *aTwo = [titles objectAtIndex:1];
            NSString *blogname = [titleTwo contents];
            NSString *blogLink = [titleTwo getAttributeNamed:@"href"];
            [article setObject:blogLink forKey:@"bloglink"];
            [article setObject:blogname forKey:@"blog"];
            [article setObject:nameOfArticle forKey:@"title"];
            [article setObject:link forKey:@"link"];
            [article setObject:author forKey:@"author"];
            [articlesDone addObject:article];
        }
    }


Вот мы и получили интересующую нас информацию о постах с сайта m.habr.ru, при этом затратили очень мало усилий и времени.

Спасибо за внимание.
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх