Как извлечь элемент таблицы из HTML-источника веб-страницы, используя селен phantomJS в Python 3? - PullRequest
1 голос
/ 03 апреля 2019

Я делаю проект веб-сканера, который должен принимать в качестве входных данных две даты (например, 2019-03-01 и 2019-03-05), а затем каждый день прикрепляется между этими двумя датами в конце базовой ссылки ( Например, базовая ссылка + дата: https://www.wunderground.com/history/daily/ir/mashhad/OIMM/date/2019-1-3). Я хочу извлечь таблицу с именем таблицы "sortable-sortable" в источнике веб-страницы и сохранить ее в текстовом файле или в любом другом формате файла.

Я разработал этот код:

from datetime import timedelta, date
from bs4 import BeautifulSoup
import urllib.request
from selenium import webdriver

class webcrawler():
    def __init__(self, st_date, end_date):
        self.base_url = 'https://www.wunderground.com/history/daily/ir/mashhad/OIMM/date/'
        self.st_date = st_date
        self.end_date = end_date

    def date_list(self):
        return [str(date1 + timedelta(n)) for n in range(int ((self.end_date - self.st_date).days)+1)]

    def create_link(self, attachment):
        url = str(self.base_url) 
        url += attachment
        return url

    def open_link(self, link):
        driver = webdriver.PhantomJS()
        driver.get(link)
        html = driver.page_source
        return html

    def extract_table(self, html):
        soup = BeautifulSoup(html)
        print(soup.prettify())

    def output_to_csv(self):
        pass

date1 = date(2018, 3, 1)
date2 = date(2019, 3, 5)

test = webcrawler(st_date=date1, end_date=date2)
date_list = test.date_list()
link = test.create_link(date_list[0])
html = test.open_link(link)
test.extract_table(html)

Проблема в том, что я так долго жду, когда получу page.source только одну ссылку. Я уже использовал urllib.request, но проблема этого метода в том, что иногда он получает html-контент, не дожидаясь полной загрузки таблицы.

Как я могу ускорить процесс и просто извлечь упомянутую таблицу и получить доступ к ее HTML-источнику, не дожидаясь остальных. Я просто хочу, чтобы информация в строках таблицы сохранялась в каком-то текстовом файле для каждой даты.

Может кто-нибудь помочь мне разобраться с проблемой?

1 Ответ

0 голосов
/ 03 апреля 2019

В этом коде и в том, как вы используете библиотеки, есть немало примечательных проблем.Позвольте мне попытаться исправить это.

Во-первых, я не вижу, чтобы вы использовали библиотеку urllib.request.Вы можете удалить это, или если вы используете его в другом месте вашего кода, я рекомендую высоко оцененный модуль запросы .Я также рекомендую использовать библиотеку запросов вместо selenium, если вы пытаетесь получить только источник HTML с сайта, поскольку selenium больше ориентирован на навигацию по сайтам и действует как «реальный» человек.

Вы можетеиспользуйте response = requests.get('https://your.url.here'), а затем response.text, чтобы получить возвращенный HTML.

Далее я заметил, что в методе open_link() вы создаете новый экземпляр класса PhantomJS каждый раз, когда вызываете метод.Это действительно неэффективно, поскольку селен использует много ресурсов (и занимает много времени, в зависимости от используемого вами драйвера).Это может быть большой вклад в ваш код работает медленнее, чем хотелось бы.Вы должны максимально использовать экземпляр driver, поскольку селен был разработан для такого использования.Отличным решением этой проблемы было бы создание экземпляра driver в методе * 1016. *

class WebCrawler():
    def __init__(self, st_date, end_date):
        self.driver = webdriver.PhantomJS()
        self.base_url = 'https://www.wunderground.com/history/daily/ir/mashhad/OIMM/date/'
        self.st_date = st_date
        self.end_date = end_date

    def open_link(self, link):
        self.driver.get(link)
        html = driver.page_source
        return html

# Alternatively using the requests library

class WebCrawler():
    def __init__(self, st_date, end_date):
        self.base_url = 'https://www.wunderground.com/history/daily/ir/mashhad/OIMM/date/'
        self.st_date = st_date
        self.end_date = end_date

    def open_link(self, link):
        response = requests.get(link)
        html = response.text
        return html

Примечание: для имен классов следует использовать CamelCase вместо строчных.Это всего лишь предложение, но оригинальный создатель python создал PEP8, чтобы определить общее руководство по стилю написания кода на python.Проверьте это здесь: Имена классов

Еще одна странная вещь, которую я обнаружил, это то, что вы приводите строку в ... строку.Вы делаете это в url = str(self.base_url).Это ничего не ранит, но и не помогает.Я не могу найти какие-либо ресурсы / ссылки, но у меня есть подозрение, что это займет дополнительное время для переводчика.Поскольку скорость имеет значение, я рекомендую использовать url = self.base_url, поскольку базовый URL-адрес уже является строкой.

Я вижу, что вы форматируете и создаете URL-адреса вручную, но если вы хотите немного больше контроля и меньшеошибки, посмотрите библиотеку furl .

def create_link(self, attachment):
        f = furl(self.base_url)

        # The '/=' operator means append to the end, docs: https://github.com/gruns/furl/blob/master/API.md#path
        f.path /= attachment

        # Cleanup and remove invalid characters in the url
        f.path.normalize()        

        return f.url  # returns the url as a string

Другая потенциальная проблема заключается в том, что метод extract_table() ничего не извлекает, он просто форматирует html так, как это делает человек.удобочитаемый.Я не буду углубляться в это, но я рекомендую изучить CSS-селекторы или XPath-селекторы для простого извлечения данных из HTML.

В методе date_list() вы пытаетесь использовать переменную date1,но не определили это нигде.Я разбил бы там лямбду и расширил бы ее на несколько строк, чтобы вы могли легко прочитать и понять, что она пытается делать.

Ниже приведен полный, переработанный, , предложенный код.

from datetime import timedelta, date
from bs4 import BeautifulSoup
import requests
from furl import furl

class WebCrawler():
    def __init__(self, st_date, end_date):
        self.base_url = 'https://www.wunderground.com/history/daily/ir/mashhad/OIMM/date/'
        self.st_date = st_date
        self.end_date = end_date

    def date_list(self):
        dates = []
        total_days = int((self.end_date - self.st_date).days + 1)

        for i in range(total_days):
            date = self.st_date + timedelta(days=i)
            dates.append(date.strftime(%Y-%m-%d))

        return dates

    def create_link(self, attachment):
        f = furl(self.base_url)

        # The '/=' operator means append to the end, docs: https://github.com/gruns/furl/blob/master/API.md#path
        f.path /= attachment

        # Cleanup and remove invalid characters in the url
        f.path.normalize()        

        return f.url  # returns the url as a string

    def open_link(self, link):
        response = requests.get(link)
        html = response.text
        return html

    def extract_table(self, html):
        soup = BeautifulSoup(html)
        print(soup.prettify())

    def output_to_csv(self):
        pass

date1 = date(2018, 3, 1)
date2 = date(2019, 3, 5)

test = webcrawler(st_date=date1, end_date=date2)
date_list = test.date_list()
link = test.create_link(date_list[0])
html = test.open_link(link)
test.extract_table(html)

...