首先,我是一名后端开发人员,大约 15 年没有尝试过解析 HTML 文档,所以请耐心等待。另外,我真的不知道 Instagram 是如何运作的,这就是我尝试了解它的原因。
我正在尝试从 Instagram 下载视频,该视频位于“视频”标签中。我一直在创建不同的方法来迭代 org.jsoup.nodes.Document 的子元素。似乎无论我做什么,我都无法识别该标签。我尝试使用类方法 Document.children().select(*)。我想知道 Instagram 是否有一些如何“隐藏”视频源的方法。我真的不知道。
我还期望有一个名为 og:video 的元标记,但这个标记不存在(标题、img 等存在)。我尝试像这样访问它:
page.select("meta[property=og:video]").first().attr("内容");
在 instagramDownloader 类中,有两个递归方法来遍历所有节点和元素,这两个方法都没有给我任何关于如何检索视频的线索。我确实在另一个堆栈溢出问题上找到了这种递归方法。我什至不知道如果我有 src URL 是否可以下载视频。
`
public class Application {
public static void main(String[] args) {
try {
login();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void login() throws IGLoginException, InterruptedException, ExecutionException{
IGClient client = IGClient.builder().username("myuser").password("mylogin").login();
InstagramDownloader dl = new InstagramDownloader();
dl.downloadVideo("https://www.instagram.com/reel/CzeWZCYJ09R/", "C:\\temp");
}
public class InstagramDownloader {
private Document page;
private final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36";
public void downloadVideo(String url, String targetDirectory){
String videoUrl = "";
Helpers.validateURL(url);
try {
page = Jsoup.connect(url).userAgent(USER_AGENT).get();
getAllElements(page);
getAllNodes(page);
//videoUrl = ???
} catch (IOException e){
e.printStackTrace();
}
download(videoUrl, targetDirectory);
}
public void getAllElements(Document doc) {
Elements children = new Elements();
recurseOverElements(doc.getAllElements(), children);
for (Element element : children) {
System.out.println(element.tagName());
}
}
public Elements recurseOverElements(Elements elementList, Elements children){
if(elementList.size() == 0)
return children;
for (Element element : elementList) {
recurseOverElements(element.children(), children);
children.add(element);
}
return children;
}
public void getAllNodes(Document doc) {
List<Node> allNodesInDom = new ArrayList<>();
recurseOverNodes(doc.childNodes(), allNodesInDom);
for (Node node : allNodesInDom) {
System.out.println(node.nodeName());
}
}
public List<Node> recurseOverNodes(List<Node> nodeList, List<Node> allChildNodeList){
if(nodeList.size() == 0)
return allChildNodeList;
for (Node node : nodeList) {
recurseOverNodes(node.childNodes(), allChildNodeList);
allChildNodeList.add(node);
}
return allChildNodeList;
}
private void download(String url, String targetDirectory){
String[] tempName = url.split("/");
String filename = tempName[tempName.length-1].split("[?]")[0];
try(InputStream inputStream = URI.create(url).toURL().openStream()){
int x = inputStream.read();
System.out.println("x" + x);
HttpURLConnection conn = (HttpURLConnection)URI.create(url).toURL().openConnection();
Path targetPath = new File(targetDirectory + File.separator + filename).toPath();
Files.copy(inputStream, targetPath, StandardCopyOption.REPLACE_EXISTING);
int BYTES_PER_KB = 1024;
double fileSize = ((double)conn.getContentLength() / BYTES_PER_KB);
} catch (IOException e){
e.printStackTrace();
}
}
我有一个坏消息要告诉你:你可以把你的代码扔进垃圾桶。你的计划在这里根本行不通。
您遇到的问题,也是您现在几乎在任何事情上都会遇到的问题,是 JSoup 无法真正解析现代网络。
问题很简单:您的浏览器下载的 HTML(即您提供给 JSoup 的内容)中几乎为零内容。相反,HTML 会导致一堆 JavaScript 运行,而 JavaScript 会执行各种网络请求,并创建更多包含实际内容的 HTML。
JSoup 只是一个 HTML 解析器。它不是一个 JavaScript 引擎。如果你想要一个 JavaScript 引擎,那真的很复杂,并且或多或少需要整个浏览器:这是一项非常繁重的工作。如果你想研究这一点,你可能想尝试一下硒。因此,JavaScript 使用其中的内容生成所有 HTML? 它并不存在于 JSoup 看到的东西中,而且 JSoup 也无法给你不存在的东西。
当您在浏览器中右键单击并从中选择“检查元素...”时,您将看到实时 DOM - 它一开始与从服务器下载的 HTML 页面相同,但可以通过它运行的 javascript 进行修改,在大多数现代网站上,它已经被 JavaScript 修改得太多了,这就是简陋的帐篷和大教堂之间的区别。
相反,选择“显示源”或仅使用
curl
获取实际 URL 并检查您想要的信息是否在 there 中。几率非常高,但事实并非如此。
如果不是,JSoup 不会帮助你。
一般网站都有用于此类事情的 API。这是适合这里工作的工具。不是“我将像浏览器一样运行并解析该视频 URL”。请注意,这会绕过审核,尤其是广告和用户管理,因此这些网站的构建者正在积极尝试与您作斗争。这并不会让你的工作变得不可能,只是 [A] 非常困难,[B] 在某些司法管辖区是非法的(糟糕的司法管辖区,但是,美国很可能就是其中之一。DMCA 不是一部写得很好的法律),并且 [ C] 常年令人头痛的维护问题。 Instagram 并没有坐以待毙。今天有效的方法明天可能就无效了。特别是如果他们在日志中注意到您正在这样做并试图阻止您。
这就是 API 存在的原因。服务器构建者简化了他们支持和不支持的内容,让您变得更简单,添加他们需要的任何身份验证来满足他们拥有的任何法律和营销需求(API 密钥等),然后他们可以提供和支持稳定的东西,而不是当他们决定稍微重新设计首页样式时破坏一半的网络。