Scraping with swift into buttons

47 views Asked by At

I want to scrap the lululemon website so that it takes the first six products that are displayed, and turns them into buttons that display the product's name, Image, and each link to the url of the item. Here is the URL that I am trying to scrape from as scene in the code below: https://shop.lululemon.com/search?Ntt=mens%20shirts

//
//  LuluProducts.swift


import SwiftUI
import UIKit
import WebKit


struct LuluProducts: View {
    @State private var productData: [ProductInfo] = []
    @State var gender: String = "Male"
    @State var clothes: String = "Shirts"
    @State private var webView = WKWebView()
    @State private var isLoaded = false
    @State private var isLoading = true
    
    struct ProductInfo: Identifiable {
        let id = UUID()
        let title: String
        let productURL: String
        let imageLink: String
    }
    
    var body: some View {
        let LulURL = createLuLURL()
        
        ZStack {
            if isLoading {
                VStack{
                    ProgressView()
                    Text("Fetching some recommended products!")
                }
            } else {
                
                
            
                List(productData) { info in
                    Button(action: {
                        openURLInSafari(urlString: info.productURL)
                    }) {
                        HStack {
                             CachedImage(urlString: info.imageLink)
                                .aspectRatio(contentMode: .fit)
                                .frame(width: 100, height: 100)
                            VStack(alignment: .leading) {
                                Text(info.title)
                                    .foregroundColor(.gray)
                            }
                        }
                    }
                }
            }
            
            WebView(webView: $webView, url: URL(string: LulURL), isLoaded: $isLoaded, onDidFinish: { webView in
                self.isLoading = false
                let script = """
                   var products = [];
                   var productElements = document.querySelectorAll('div.product-tile');
                   for (var i = 0; i < productElements.length && i < 6; i++) {
                       var productElement = productElements[i];
                       var title = productElement.querySelector('.product-card__title').innerText;
                       var link = productElement.querySelector('.product-card__link').getAttribute('href');
                       var img = productElement.querySelector('.product-card__image').getAttribute('srcset');
                       if (link && img) {
                           products.push({
                               title: title,
                               productURL: link,
                               imageLink: img,
                           });
                       }
                   }
                   products;
               """



                webView.evaluateJavaScript(script) { result, error in
                    if let productInfoArray = result as? [[String: String]], !productInfoArray.isEmpty {
                        self.productData = productInfoArray.map { dict in
                            ProductInfo(title: dict["title"] ?? "",
                                        productURL: dict["productURL"] ?? "",
                                        imageLink: dict["imageLink"] ?? "" )
                        }
                    } else if let error = error {
                        print("JavaScript execution failed: \(error)")
                    }
                    print("JavaScript result: \(String(describing: result))")

                }
            })
            .frame(width: 0, height: 0)
            .opacity(0)
        }
    }
    
    func createLuLURL() -> String {
        var LulURL = ""
        if gender == "Male" {
            if clothes == "Shirts" {
                LulURL = "https://shop.lululemon.com/search?Ntt=mens%20shirts"
            }
            if clothes == "Hoodies" {
                LulURL = "https://shop.lululemon.com/search?Ntt=mens%20hoodies"
            }
            if clothes == "Pants" {
                LulURL = "https://shop.lululemon.com/search?Ntt=mens%20pants"
            }
        }
        else {
            if clothes == "Shirts" {
                LulURL = "https://shop.lululemon.com/search?Ntt=womens%20shirts"
            }

            if clothes == "Hoodies" {
                LulURL = "https://shop.lululemon.com/search?Ntt=womens%20hoodies"
            }

            if clothes == "Pants" {
                LulURL = "https://shop.lululemon.com/search?Ntt=womens%20pants"
            }
        }
        return LulURL
    }

    func openURLInSafari(urlString: String) {
        if let url = URL(string: urlString) {
            UIApplication.shared.open(url)
        }
    }

    struct WebView: UIViewRepresentable {
        @Binding var webView: WKWebView
        let url: URL?
        @Binding var isLoaded: Bool
        let onDidFinish: ((WKWebView) -> Void)?

        func makeUIView(context: Context) -> WKWebView {
            webView.navigationDelegate = context.coordinator
            return webView
        }

        func updateUIView(_ uiView: WKWebView, context: Context) {
            guard !isLoaded, let url = url else { return }
            let request = URLRequest(url: url)
            uiView.load(request)
            isLoaded = true
        }

        func makeCoordinator() -> Coordinator {
            Coordinator(self)
        }

        class Coordinator: NSObject, WKNavigationDelegate {
            var parent: WebView

            init(_ parent: WebView) {
                self.parent = parent
            }

            func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
                parent.onDidFinish?(webView)
            }
        }
    }

    class ImageCache {
        private var cache = NSCache<NSString, UIImage>()

        static let shared = ImageCache()

        func getImage(urlString: String) -> UIImage? {
            return cache.object(forKey: urlString as NSString)
        }

        func setImage(image: UIImage, urlString: String) {
            cache.setObject(image, forKey: urlString as NSString)
        }
    }

    class ImageLoader: ObservableObject {
        @Published var image: UIImage?
        private var urlString: String

        init(urlString: String) {
            self.urlString = urlString
            loadImage()
        }

        private func loadImage() {
            // Check if the image is already cached
            if let cachedImage = ImageCache.shared.getImage(urlString: urlString) {
                self.image = cachedImage
                return
            }

            // Image not cached, download it
            guard let url = URL(string: urlString) else { return }

            let task = URLSession.shared.dataTask(with: url) { data, response, error in
                guard let data = data, let loadedImage = UIImage(data: data) else { return }

                DispatchQueue.main.async {
                    // Cache the downloaded image
                    ImageCache.shared.setImage(image: loadedImage, urlString: self.urlString)
                    self.image = loadedImage
                }
            }

            task.resume()
        }
    }

    struct CachedImage: View {
        @ObservedObject private var loader: ImageLoader

        init(urlString: String) {
            loader = ImageLoader(urlString: urlString)
        }

        var body: some View {
            if let image = loader.image {
                Image(uiImage: image)
                    .resizable()
            } else {
                ProgressView()
            }
        }
    }
}

struct LuluProducts_Preview: PreviewProvider {
    static var previews: some View {
        LuluProducts()
    }
}

I have tried manually changing the parameters of the script using the html of the page, but no matter what I do the page still comes out as blank. I just want 6 buttons that pull the very first 6 items for each category that link to the item's safari page when pressed

0

There are 0 answers