I’m working on a SwiftUI application that fetches media content from Instagram posts. While I can successfully retrieve a single reel from a post, my code struggles with posts containing more than two videos. The main challenge is fetching all video URLs from a multi-media post without manually clicking the ‘next’ button, as the content loads dynamically in the DOM.
Here’s the part of my code that deals with media fetching:
import SwiftUI
import WebKit
class Coordinator: NSObject, WKNavigationDelegate {
private let scripts = [
"mediaSrcScript": """
var postContainer = document.querySelector('article'); // Targeting the main post container
var nextButton = postContainer.querySelector('button[aria-label="Next"]');
var videoUrls = [];
var maxClicks = 10; // Limit the number of iterations to prevent infinite loops
function collectVideos() {
var videoElements = postContainer.querySelectorAll('video');
Array.from(videoElements).forEach(video => {
var src = video.getAttribute('src');
if (!videoUrls.includes(src)) {
videoUrls.push(src);
}
});
}
function clickNextAndCollect() {
if (nextButton && maxClicks > 0) {
nextButton.click();
maxClicks--;
setTimeout(() => {
collectVideos();
clickNextAndCollect();
}, 1000); // Delay to allow for loading new content
}
}
collectVideos();
clickNextAndCollect();
JSON.stringify(videoUrls);
""",
]
// Function called when a web page finishes loading
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
startElementCheck(webView)
}
private func startElementCheck(_ webView: WKWebView) {
let elementCheckScript = """
var profilePicExists = Array.from(document.querySelectorAll('img')).some(img => img.alt.includes('profile picture'));
profilePicExists; // Returns true if the profile picture exists
"""
webView.evaluateJavaScript(elementCheckScript) { [weak self] (result, error) in
guard let self = self, let elementReady = result as? Bool else {
return
}
if elementReady {
// Profile picture found - start executing your scripts
self.executeScripts(webView)
}
}
}
// Function to execute the scripts
private func executeScripts(_ webView: WKWebView) {
for (key, script) in self.scripts {
webView.evaluateJavaScript(script) { (result, error) in
if let resultString = result as? String {
// Process the result
print("(key): (resultString)")
} else if let error = error {
print("Error executing script (key): (error)")
}
}
}
}
}
// WebView to integrate WKWebView in SwiftUI
struct WebView: UIViewRepresentable {
let url: URL
func makeUIView(context: Context) -> WKWebView {
let webView = WKWebView()
webView.navigationDelegate = context.coordinator
return webView
}
func updateUIView(_ uiView: WKWebView, context: Context) {
let request = URLRequest(url: url)
uiView.load(request)
}
func makeCoordinator() -> Coordinator {
return Coordinator()
}
}
// ContentView to display the WebView
struct ContentView: View {
var body: some View {
WebView(url: URL(string: "https://www.instagram.com/p/Cz45oeXJhj8/?utm_source=ig_web_copy_link")!)
}
}
The code successfully gets the first two video URLs, but then I have to start clicking ‘next’ to fetch more, which isn’t ideal or is not working. I’m looking for a way to automatically load and process all video URLs from a post. Does anyone know a more efficient method to fix this, possibly without relying on UI interactions?