
Gibt es eine Möglichkeit, die Hyperlinks einer pdf
Datei zu testen? Angenommen, ich habe eine pdf
Datei mit einer großen Anzahl von Hyperlinks. Kann ich dann automatisch testen, welche Antwort ich erhalte, wenn ich diesen Links folge ( 200
= ok, 404
= nicht gefunden usw.).
Ich weiß, dass es solche Tools für Webseiten gibt (als Software, wieKLinkStatusoder als Webservices, wieder Checklink des W3C), aber gibt es ein Äquivalent für pdf
? Da es so etwas vermutlich nicht gibt, gibt es ein gutes Äquivalent für tex
Dateien? Ich vermute, das lässt sich mit einigen Skripten und Regexp-Magie bewerkstelligen, aber ich habe mich gefragt, ob es dafür bereits eine Lösung gibt.
\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}
Antwort1
Installieren Sie curl (vorausgesetzt, Sie verwenden apt-get zum Installieren von Paketen):
sudo apt-get install curl
und gehen Sie für PDF-Dateien wie folgt vor:
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
und gehen Sie wie folgt für Tex-Dateien vor:
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
Kopieren Sie für einen sofortigen Test Folgendes und fügen Sie es in Ihre Befehlszeile ein:
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
Weitere Einzelheiten finden Sie unter:
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
Antwort2
Wenn Sie mit der Verwendung von Python vertraut sind, reicht dies möglicherweise aus.
Ich verwende Python mit den Paketen pyPdf und urllib2. Die Logik ist wie folgt: Öffnen Sie eine PDF-Datei mit pyPdf.PdfFileReader und durchlaufen Sie sie. In der folgenden Funktion pdf
ist das geöffnete PDF-Dateiobjekt.
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
Das url_checker
öffnet die URL und gibt im Fehlerfall zurück (False, error_string)
. Andernfalls gibt es zurück(True, None)
Am Ende des Vorgangs verfügen Sie über eine Liste der URLs im PDF-Dokument, aller fehlerhaften URLs, die nicht geöffnet werden konnten (mit Angabe des Grundes), eine Liste der Links im PDF-Dokument und eine Teilmenge der Links, die keine Zielanker haben.
Ich habe die Logik für den URL-Checker weggelassen, aber sie ist ziemlich einfach. Es gibt mehrere Möglichkeiten, diesen Teil zu erledigen – Sie können auch das requests
Paket anstelle von verwenden urllib2
.
Antwort3
Ein einfaches C++-Programm mit Qt4 und Poppler würde es tun. Ich habe es schnell skizziert und an einigen PDFs getestet. Ich denke, man könnte es noch viel optimieren, um es robuster gegen seltsame Links wie mailto: -protocol und andere Ports zu machen. Und natürlich kann die Ausgabeformatierung besser sein, wenn man sie anschließend analysieren muss, aber es erfüllt seinen Zweck.
#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;
}
Da ich ein CMake-Freund bin, habe ich diese CMakeLists.txt zum Kompilieren verwendet:
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})
Sie benötigen Qt4-Entwicklungspakete und Poppler-Qt4-Entwicklungspakete. Wenn Sie kein FindPoppler.cmake in Ihren CMakeModules-Verzeichnissen haben, holen Sie sich eines online.
Um es zu kompilieren, stellen Sie sicher, dass sich im Projektverzeichnis qlinkextract befindet (muss genau wie folgt geschrieben werden):
- CMakeLists.txt (siehe oben)
- main.cpp (siehe oben)
- cmake/Modules/FindPoppler.cmake (von irgendwo herunterladen)
- build/ (Ordner ist optional)
Gehen Sie auf einer Konsole zum Build-Ordner und geben Sie ein
cmake ..
make
wenn etwas fehlt, installieren Sie die fehlenden Pakete
Einige Beispielausgaben:
"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