Swift просматривает веб-страницу, используя регулярные выражения - PullRequest
0 голосов
/ 08 марта 2020

Сначала смотрите обновления ниже.

Я пытаюсь очистить все модераторы для указанного sub-reddit на reddit. API только позволяет вам получить все имена пользователей модераторов для sub-reddit, поэтому сначала я получил все это, а затем выполнил дополнительный запрос для каждого из этих профилей, чтобы получить URL аватара. Это закончилось тем, что превысило лимит API.

Поэтому вместо этого я хочу просто получить источник следующей страницы и разбить его на страницы, собирая 10 имен пользователей и URL-адреса аватаров на каждой странице. Это приведет к опросу сайта с меньшим количеством запросов. Я понимаю, как выполнять разбиение на страницы, но сейчас я пытаюсь понять, как собрать имена пользователей и примыкающие URL аватара.

Итак, возьмите следующий URL:

https://www.reddit.com/r/videos/about/moderators/

Так что я буду потяните весь исходный код страницы,

Добавьте все имена пользователей и ссылки на моды в объект мода, затем в массив.

Было бы неплохо использовать регулярное выражение в строке, которую я получаю?

Это мой код, любая помощь будет полезна:

    func tester() {
       let url = URL(string: "https://www.reddit.com/r/videos/about/moderators")!

       let task = URLSession.shared.dataTask(with: url) { data, response, error in
           guard let data = data, error == nil else {
               print("\(error)")
               return
           }

        let string = String(data: data, encoding: .utf8)

            let regexUsernames = try? NSRegularExpression(pattern: "href=\"/user/[a-z0-9]\"", options: .caseInsensitive)

            var results = regexUsernames?.matches(in: string as String, options: [], range: NSRange(location: 0, length: string.length))

            let regexProfileURLs = try? NSRegularExpression(pattern: "><img src=\"[a-z0-9]\" style", options: .caseInsensitive)

           print("\(results)") // This shows as empty array
       }

       task.resume()
   }

У меня есть также пробовал следующее, но получаю эту ошибку:

Can't form Range with upperBound < lowerBound

Код:

    func tester() {
       let url = URL(string: "https://www.reddit.com/r/videos/about/moderators")!

       let task = URLSession.shared.dataTask(with: url) { data, response, error in
           guard let data = data, error == nil else {
            print("data was nil")
               return
           }

        guard let htmlString = String(data: data, encoding: .utf8) else {
            print("cannot cast data into string")
            return
        }

        let leftSideOfValue = "href=\"/user/"
        let rightSideOfValue = "\""

        guard let leftRange = htmlString.range(of: leftSideOfValue) else {
            print("cannot find range left")
            return
        }

        guard let rightRange = htmlString.range(of: rightSideOfValue) else {
            print("cannot find range right")
            return
        }

        let rangeOfTheValue = leftRange.upperBound..<rightRange.lowerBound

        print(htmlString[rangeOfTheValue])
}

ОБНОВЛЕНИЕ:

Итак, я дошел до того, что он даст мне первое имя пользователя, однако я зацикливаюсь и просто получаю одно и то же снова и снова. Как лучше всего двигаться на каждом шаге? Есть ли способ сделать что-то вроде let newHTMLString = htmlString.dropFirst (k:?), Чтобы заменить htmlString подстрокой, которая находится после элементов, которые мы только что получили?

func tester() {
       let url = URL(string: "https://www.reddit.com/r/pics/about/moderators")!

       let task = URLSession.shared.dataTask(with: url) { data, response, error in
           guard let data = data, error == nil else {
            print("data was nil")
               return
           }

        guard let htmlString = String(data: data, encoding: .utf8) else {
            print("cannot cast data into string")
            return
        }


        let counter =  htmlString.components(separatedBy:"href=\"/user/")
        let count = counter.count

        for  i in 0...count {

            let leftSideOfUsernameValue = "href=\"/user/"
            let rightSideOfUsernameValue = "\""

            let leftSideOfAvatarURLValue = "><img src=\""
            let rightSideOfAvatarURLValue = "\">"


          guard let leftRange = htmlString.range(of: leftSideOfUsernameValue) else {
                print("cannot find range left")
                return
            }

            guard let rightRange = htmlString.range(of: rightSideOfUsernameValue) else {
                print("cannot find range right")
                return
            }

            let username = htmlString.slice(from: leftSideOfUsernameValue, to: rightSideOfUsernameValue)
            print(username)
            guard let avatarURL = htmlString.slice(from: leftSideOfAvatarURLValue, to: rightSideOfAvatarURLValue) else {
                print("Error")
                return
            }
            print(avatarURL)

        }

       }

       task.resume()
   }

Я также пробовал:

           let endString = String(avatarURL + rightSideOfAvatarURLValue)
            let endIndex = htmlString.index(endString.endIndex, offsetBy: 0)
            let substringer = htmlString[endIndex...]
            htmlString = String(substringer)

1 Ответ

2 голосов
/ 09 марта 2020

Вы должны иметь возможность извлекать все имена и URL-адреса в два отдельных массива, вызывая простое регулярное выражение, выполняя что-то вроде:

func tester() {
    let url = URL(string: "https://www.reddit.com/r/pics/about/moderators")!

    let task = URLSession.shared.dataTask(with: url) { data, response, error in
        guard let data = data, error == nil else { return }
        guard let htmlString = String(data: data, encoding: .utf8) else { return }

        let names = htmlString.matching(regex: "href=\"/user/(.*?)\"")
        let imageUrls = htmlString.matching(regex: "><img src=\"(.*?)\" style")
        print(names)
        print(imageUrls)
    }
    task.resume()
}

extension String {
    func matching(regex: String) -> [String] {
        guard let regex = try? NSRegularExpression(pattern: regex, options: []) else { return [] }
        let result  = regex.matches(in: self, options: [], range: NSMakeRange(0, self.count))
        return result.map {
            return String(self[Range($0.range, in: self)!])
        }
    }
}

или , вы можете создать объект для каждого из <div class="_1sIhmckJjyRyuR_z7M5kbI">, а затем возьмите имена и URL для использования по мере необходимости.

...