Извлечение URL из буфера Emacs? - PullRequest
3 голосов
/ 29 октября 2009

Как мне написать функцию Emacs Lisp, чтобы найти все hrefs в файле HTML и извлечь все ссылки?

Введите:

<html>
 <a href="http://www.stackoverflow.com" _target="_blank">StackOverFlow&lt/a>
 <h1>Emacs Lisp</h1>
 <a href="http://news.ycombinator.com" _target="_blank">Hacker News&lt/a>
</html>

Выход:

http://www.stackoverflow.com|StackOverFlow
http://news.ycombinator.com|Hacker News

Я видел функцию повторного поиска вперед, упомянутую несколько раз во время моего поиска. Вот то, что я думаю, что мне нужно сделать, основываясь на том, что я прочитал до сих пор.

(defun extra-urls (file)
 ...
 (setq buffer (...
 (while
        (re-search-forward "http://" nil t)
        (when (match-string 0)
...
))

Ответы [ 3 ]

5 голосов
/ 01 ноября 2009

Я принял решение Хайнци и придумал окончательное решение, в котором я нуждался. Теперь я могу взять список файлов, извлечь все URL и заголовки и поместить результаты в один выходной буфер.

(defun extract-urls (fname)
 "Extract HTML href url's,titles to buffer 'new-urls.csv' in | separated format."
  (setq in-buf (set-buffer (find-file fname))); Save for clean up
  (beginning-of-buffer); Need to do this in case the buffer is already open
  (setq u1 '())
  (while
      (re-search-forward "^.*<a href=\"\\([^\"]+\\)\"[^>]+>\\([^<]+\\)</a>" nil t)

      (when (match-string 0)            ; Got a match
        (setq url (match-string 1) )    ; URL
        (setq title (match-string 2) )  ; Title
        (setq u1 (cons (concat url "|" title "\n") u1)) ; Build the list of URLs
       )
      )
  (kill-buffer in-buf)          ; Don't leave a mess of buffers
  (progn
    (with-current-buffer (get-buffer-create "new-urls.csv"); Send results to new buffer
      (mapcar 'insert u1))
    (switch-to-buffer "new-urls.csv"); Finally, show the new buffer
    )
  )

;; Create a list of files to process
;;
(mapcar 'extract-urls '(
                       "/tmp/foo.html"
                       "/tmp/bar.html"
               ))

2 голосов
/ 29 октября 2009

Если в строке содержится не более одной ссылки и вы не возражаете против какого-то очень уродливого взлома регулярных выражений, запустите следующий код в буфере:

(defun getlinks ()
  (beginning-of-buffer)
  (replace-regexp "^.*<a href=\"\\([^\"]+\\)\"[^>]+>\\([^<]+\\)</a>.*$" "LINK:\\1|\\2")
  (beginning-of-buffer)
  (replace-regexp "^\\([^L]\\|\\(L[^I]\\)\\|\\(LI[^N]\\)\\|\\(LIN[^K]\\)\\).*$" "")
  (beginning-of-buffer)
  (replace-regexp "
+" "
")
  (beginning-of-buffer)
  (replace-regexp "^LINK:\\(.*\\)$" "\\1")
)

Он заменяет все ссылки на LINK: url | description, удаляет все строки, содержащие что-либо еще, удаляет пустые строки и, наконец, удаляет «LINK:».

Подробный HOWTO: (1) Исправьте ошибку в вашем html-файле примера, заменив <href на <a href, (2) скопируйте вышеупомянутую функцию в царапину Emacs, (3) нажмите Cx Ce после последнего ")" чтобы загрузить функцию, (4) загрузите ваш пример HTML-файла, (5) выполните функцию с помощью M-: (getlinks).

Обратите внимание, что разрывы строк в третьем replace-regexp важны. Не отступайте от этих двух строк.

1 голос
/ 29 октября 2009

Вы можете использовать библиотеку 'xml, примеры использования парсера можно найти здесь . Чтобы проанализировать ваш конкретный файл, следующее делает то, что вы хотите:

(defun my-grab-html (file)
  (interactive "fHtml file: ")
  (let ((res (car (xml-parse-file file)))) ; 'car because xml-parse-file returns a list of nodes
    (mapc (lambda (n)
            (when (consp n) ; don't operate on the whitespace, xml preserves whitespace
              (let ((link (cdr (assq 'href (xml-node-attributes n)))))
                (when link
                  (insert link)
                  (insert "|")
                  (insert (car (xml-node-children n))) ;# grab the text for the link
                  (insert "\n")))))
          (xml-node-children res))))

Это не рекурсивно анализирует HTML, чтобы найти все ссылки, но должно помочь вам начать работу в направлении общего решения.

...