Pruebe los hipervínculos de un documento pdf

Pruebe los hipervínculos de un documento pdf

¿Hay alguna forma de probar los hipervínculos de un pdfarchivo? Supongamos que tengo un pdfarchivo que contiene una gran cantidad de hipervínculos, ¿puedo probar automáticamente la respuesta que tendré al seguir esos enlaces ( 200= ok, 404= no encontrado, etc.)?

Sé que existen herramientas de este tipo para páginas web (como software, comoEstado de enlace K, o como servicios web, comoel checklink del W3C) pero ¿hay algún equivalente para pdf? Como supongo que no existe tal cosa, ¿existe algún buen equivalente para texlos archivos? Supongo que esto se puede hacer con algunos scripts y expresiones regulares mágicas, pero me preguntaba si existía alguna solución.

\documentclass{article}
\usepackage{hyperref}

\begin{document}
\href{http://tex.stackexchange.com/test-404/}{This will give a 404}

\href{http://tex.stackexchange.com/}{This will give a 200}

\end{document}

Respuesta1

Instale curl (suponiendo que use apt-get para instalar paquetes):

sudo apt-get install curl

y haga lo siguiente para archivos pdf:

cat document.pdf | grep -ao '[a-zA-Z]\+://[a-zA-Z.-]*[^)]\+' | while read LINE; do curl -o /dev/null --silent --head --write-out '%{http_code}' "$LINE";    echo " $LINE";  done

y haga lo siguiente para archivos tex:

cat myfile.tex | grep -o '{[a-zA-Z]\+://[a-zA-Z.-]*[^}]\+}' | sed s/{// | sed s/}// | while read LINE; do curl -o /dev/null --silent --head --write-out '%{http_code}' "$LINE" echo " $LINE" done

Copie y pegue lo siguiente en su línea de comando para una prueba inmediata:

echo "\documentclass{article}
\usepackage{hyperref}

\begin{document}
\href{http://tex.stackexchange.com/test-404/}{This will give a 404}

\href{http://tex.stackexchange.com/}{This will give a 200}

\end{document}" | grep -o '{[a-zA-Z]\+://[a-zA-Z.-]*[^}]\+}' | sed s/{// | sed s/}// | while read LINE; do
   curl -o /dev/null --silent --head --write-out '%{http_code}' "$LINE"
   echo " $LINE"
 done

Consulte lo siguiente para obtener más detalles:

https://stackoverflow.com/questions/13611973/how-to-grep-for-a-url-in-a-file https://stackoverflow.com/questions/6136022/script-to-get-the-http-status-code-of-a-list-of-urls

Respuesta2

Si está dispuesto a utilizar Python, esto puede ser suficiente.

Utilizo Python con los paquetes pyPdf y urllib2. La lógica es la siguiente: abra un pdf con pyPdf.PdfFileReader y recorralo. En la siguiente función, pdfestá el objeto de archivo pdf abierto.

def get_urls(pdf):
    badurls = list()
    links = list()
    url_checker = URLChecker() # a helper function to test the URL (urllib2)
    for pg in range(pdf.getNumPages()):
        page = pdf.getPage(pg)
        obj = page.getObject()

        for a in obj.get('/Annots', []):
            u = a.getObject()
            lnk = u['/A'].get('/D')
            url = u['/A'].get('/URI')
            if lnk:
                links.append(lnk)
            if url:
                urls.append(url)
                result, reason = url_checker.check(url)
                if not result:
                    badurls.append({'url':url, 'reason': '%r' % reason})

    anchors = pdf.getNamedDestinations().keys()
    badlinks = [x for x in links if x not in anchors]
    return urls, badurls, badlinks

Abre url_checkerla URL y si hay un error, devuelve (False, error_string). De lo contrario regresa(True, None)

Entonces, al final del proceso, tiene una lista de URL en el PDF, todas las URL incorrectas que no se pudieron abrir (que contienen el motivo), una lista de enlaces en el PDF y un subconjunto de aquellos enlaces que no tener anclajes de destino.

Omití la lógica de url_checker, pero es bastante simple. Hay varias formas de hacer esa parte; también puedes usar el requestspaquete en lugar de urllib2.

Respuesta3

Un programa simple en C++ que use Qt4 y Poppler sería suficiente. Rápidamente lo esbocé y lo probé en algunos archivos PDF. Creo que se podrían modificar mucho para hacerlo más robusto contra enlaces extraños como mailto: -protocol y otros puertos. Y, por supuesto, el formato de salida puede ser mejor si necesita analizarlo después, pero funciona.

#include <QTcpSocket>
#include <QUrl>
#include <QByteArray>
#include <QList>
#include <poppler-qt4.h>
#include <QDebug>

  using namespace Poppler;

  QString urlGetStatus(const QUrl &url) {
    QString status;
    QTcpSocket socket;
    socket.connectToHost(url.host(), 80);
    if (socket.waitForConnected()) {
        socket.write("HEAD " + url.path().toUtf8() + " HTTP/1.1\r\n"
                     "Host: " + url.host().toUtf8() + "\r\n"
                     "\r\n");
        if (socket.waitForReadyRead()) {
                QByteArray bytes = socket.readAll();
                status = QString(bytes).mid(9, 3);
        }
    }
    return status;
  }

  int main(int argc, char *argv[]) {
    if(argc < 2) {
        return 1;
    }
    QString path = QString(argv[1]);
    Document *doc = Document::load(path);
    if(doc == NULL)
        return 1;
    QList<QUrl> urlList;
    for(int i = 0;i < doc->numPages(); i++) {        
        Page *p = doc->page(i);
        foreach(Link *li,p->links()) {
            if(li->linkType() == Link::Browse) {
                LinkBrowse *link = static_cast<LinkBrowse*>(li);
                urlList.append(QUrl(link->url()));
            }
        }
    }
    foreach(QUrl url, urlList) {
        QString stat = urlGetStatus(url);
        if(stat == "200") {
            qDebug() << url.toString() << "returned status 200";
        } else {
            qDebug() << url.toString() << " maybe not reachable status" << stat;
        }
    }
    return 0;
  }

Como soy amigo de cmake, utilicé este CMakeLists.txt para compilar:

cmake_minimum_required(VERSION 2.6)
project(qlinkextract)
set (CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/Modules/")

find_package(Qt4 REQUIRED QtCore QtNetwork)
include(${QT_USE_FILE})

find_package(Poppler REQUIRED)
include_directories(${POPPLER_QT_INCLUDE_DIR})

add_executable(qlinkextract main.cpp)
target_link_libraries(qlinkextract ${QT_LIBRARIES} ${POPPLER_QT_LIBRARIES})

Necesitará paquetes de desarrollo Qt4 y paquetes de desarrollo Poppler-Qt4. Si no tiene un FindPoppler.cmake en sus directorios de CMakeModules, obtenga uno en línea.

Para compilarlo, asegúrese de que en el directorio del proyecto esté qlinkextract (debe escribirse exactamente como se muestra a continuación)

  • CMakeLists.txt (ver arriba)
  • main.cpp (ver arriba)
  • cmake/Modules/FindPoppler.cmake (descargar desde algún lugar)
  • build/ (la carpeta es opcional)

en una consola, vaya a la carpeta de compilación y escriba

cmake ..
make

si falta algo, instale los paquetes que faltan

Algunos resultados de ejemplo:

"http://www.igi-global.com/chapter/ontology-based-multimedia-indexing/42895?camid=4v1" returned status 200 
"http://www.igi-global.com/chapter/ontology-based-multimedia-indexing/42895?camid=4v1" returned status 200 
"http://www.igi-global.com/e-resources/library-recommendation/?id=1" returned status 200 
"http://www.igi-global.com/chapter/towards-low-cost-energy-monitoring/112719?camid=4v1a" returned status 200 
"http://www.igi-global.com/article/algebraic-properties-of-rough-set-on-two-universal-sets-based-on-multigranulation/116046?camid=4v1a" returned status 200 
"http://www.igi-global.com/article/algebraic-properties-of-rough-set-on-two-universal-sets-based-on-multigranulation/116046?camid=4v1a" returned status 200 
"http://www.igi-global.com/article/fuzzy-decision-support-system-for-coronary-artery-disease-diagnosis-based-on-rough-set-theory/111313?camid=4v1a" returned status 200 
"http://www.igi-global.com/article/fuzzy-decision-support-system-for-coronary-artery-disease-diagnosis-based-on-rough-set-theory/111313?camid=4v1a" returned status 200 
"http://www.igi-global.com/chapter/optimization-model-identification-temperature-intelligent/74536?camid=4v1a" returned status 200 
"http://www.igi-global.com/chapter/optimization-model-identification-temperature-intelligent/74536?camid=4v1a" returned status 200 

información relacionada