На основе инструмента автоматического тестирования браузера webdriver.
Обратите внимание, что эта статья была написана 992 дня назад и последний раз изменялась 992 дня назад, поэтому некоторая информация может быть устаревшей.
Эта программа используется только для личного обучения программированию и строго запрещена для вредоносных атак на веб-сайты. Просканированные данные строго запрещены к продаже, распространению или использованию в коммерческих целях! ! !
класс сбора данных рептилия на основе определенного сайта государственных торгов,Можно получить информацию о тендерном проекте。использоватьPython
изselenium
Работа модуля Браузер Инструменты автоматического тестированияwebdriver
бежать。
Соответствующую информацию можно получить:
бегатьпрограмманазад。Ползтиданные Сохранить впрограмма В той же папкеизBiddingInfo.json
середина。
Точность данных:
Поскольку информация объявления о победившей ставке на этом веб-сайте не имеет единого формата, может не получиться подробная информация о выигравшей ставке (например, сумма выигрышной ставки и выигрышная единица), поэтому необходимо выполнить соответствующую обработку. в соответствии с различными форматами разных страниц.
Эффективность программы:
Поскольку он основан на Браузер Инструменты автоматического тестированияselenium
,Так что эффективность не обязательно будет слишком высокой.,Но преимущество да в том, что вы можете наблюдать за ситуацией со сканированием данных в режиме реального времени.,Немедленно прекратите работу в случае аварии.
Как показано на картинке:использоватьxpathграмматика//tbody//td[2]
получатьизи Неавесьtbodyсерединаизвторойtd
элемент,идаtbody
следующий уровеньсерединавсеизвсеиз Уровень 2изtd
элемент。
Пример скриншота
существоватьselenium
модульизиспользоватьсередина,не может быть напрямуюиспользоватьxpath
грамматикаполучатьэлемент Внутренние персонажи,потому чтоselenium
грамматика Просьба найтииз Объект должендаhtmlэлемент,Не могу натянуть строку. Вы не можете использовать синтаксис XPath для прямого получения текста внутри метки:
temp_dict['legal_person'] = self.driver.find_element_by_xpath("//tbody/tr[2]/td[2]/text()") # Юридическое лицо проекта
temp_dict['time'] = self.driver.find_element_by_xpath("//tbody/tr[5]/td[4]/text()") # время
Сообщит об ошибке:
Message: invalid selector: The result of the xpath expression "//tbody/tr[2]/td[2]/text()" is: [object Text]. It should be an element.
Вопросы, возникшие ранее:
использоватьxpath
При позиционировании,Лучше сначала прокрутить окно Браузера на экран,В противном случае получение элемента будет неточным.,Иногда я до сих пор не могу этого понять,Не думайте, что пока элемент находится в текущем html-документе, вы можете его получить! ! !
xpath
получатьтекст в элементеиз Два необходимых условия:
Решение может быть достигнуто путем перемещения мыши и выполнения функции JS прокрутки страницы.
Неявное ожидание бесполезно,Иногда элементы уже можно увидеть в интерфейсе Браузера,нодаполучатьэлементизtext
возвращатьсядаполучатьменьше, чем,нуждатьсяиспользоватьtime.sleep()
вынужденное ожидание。
Почему это происходит?
существоватьhtml
элемент Внутри,некоторыйэлемент ХотясуществоватьDOM
документсередина,нода Долженэлементизcss
действительно свойстваdisplay: none;
,ик этомуэлементпрямойиспользоватьelement.txt
даполучатьменьше, чемценитьиз,потому чтопотому чтоwebdriver specизопределение,Selenium WebDriver Будет взаимодействовать только с видимыми элементами, поэтому получение текста скрытых элементов всегда будет возвращать пустую строку (этой проблемы не существует при использовании Scrapy Framework).
в этих случаях,我们нуждатьсяполучатьскрыватьэлементизтекст。这些Внутри容可以использоватьelement.get_attribute('attributeName')
методполучать,проходитьtextContent
, innerText
, innerHTML
характеристикиполучатьценить。
innerHTML
вернет внутреннюю часть элемента HTML,Содержит все HTML-теги (например.,<div>Hello <p>World!</p></div>
изinnerHTML
получитHello <p>World!</p>)
。
textContent
и innerText
получит только текстовый контент, а не HTML Этикетка(textContent
да W3C Совместимые атрибуты текстового контента, но да IE Не поддерживается;innerText
Неа W3C DOM Указанный контент не поддерживается FireFox).
существоватьA页面保存了大量нуждаться跳转页面изurl
,Если программа совершает прыжок,тогда сохрани раньшеизurl
исчезнет,Вам нужно использовать переменную (например: массив), чтобы сохранить все ссылки перед переходом.
# Определите массив для временного хранения всех URL-адресов этой страницы.
temp_url_list = []
# Перейти на страницу сведений о проекте
for item in project_list:
# print(item.get_attribute('href'), type(item.get_attribute('href')))
temp_url_list.append(item.get_attribute('href'))
print(f"Получить данные {len(temp_url_list)}" на странице {self.counter})
for url in temp_url_list:
self.blank_in_detail(url)
# print(project_list[0].get_attribute('href')) # Можно печатать нормально
# for item in project_list:
# self.blank_in_detail(item.get_attribute('href'))
# print(project_list[0].get_attribute('href')) # Невозможно нормально распечатать! Данные исчезают после перехода на страницу!!!
import re
string = '''
S11 Объявление о победе в тендере на строительство трубопровода скоростной автомагистрали Уху-Хуаншань
«Строительство трубопровода скоростной автомагистрали S11 Уху-Хуаншань (номер проекта: 2020DFAGZ01853/GC20200417002-wxgd)» Работа по оценке торгов завершена, и победитель торгов определен. Победившая заявка теперь объявляется следующим образом:
Имя победителя торгов: Zhonghui Construction Technology Co., Ltd.
Сумма выигрышной ставки: Одна тысяча семьсот семьдесят восемь тысяч юаней округляется (¥17678000,0000).
'''
print(re.search(r'Сумма выигрышной ставки(.*?)([\d+\.]+)(\)?)', string).group(2)) # 17678000.0000
r
Предотвратить экранирование строки;*?
Указывает нежадный режимполучать,проходитьсуществовать *、+ или ? размещен после квалификации ?,Выражение преобразуется из «жадного» выражения в «нежадное» выражение или минимальное совпадение.from selenium import webdriver
import time
import random
import re
import openpyxl
import json
# Создать класс рептилий
class BiddingInfo(object):
def __init__(self):
'''
Инициализация объекта
'''
self.start_url = ''
self.file = open('BiddingInfo.json', 'w',
encoding='utf-8') # Установите начальный формат, чтобы предотвратить искажение символов после сохранения.
self.counter = 0 # Счетчик перелистывания страниц
def run(self):
'''
Определить функцию ввода объекта
'''
self.get_web_gage()
while True:
return_mark = self.get_list()
if return_mark:
self.jump_into_iframe() # Поскольку вы входите на страницу сведений о проекте, вам необходимо повторно ввести рамку после того, как окно вернется обратно.
self.click_next_page()
def get_web_gage(self):
'''
Построить Браузер для мониторинга и отправки запросов
'''
self.driver = webdriver.Chrome()
self.driver.get(self.start_url)
self.driver.implicitly_wait(10) # Неявное ожидание, до 20 секунд
self.move_search_btn() # При первом открытии окна необходимо нажать кнопку поиска
self.jump_into_iframe()
def jump_into_iframe(self):
'''
Наведите драйвер страницы на переход во фреймрамку.
'''
frame = self.driver.find_element_by_id('infoframe') # Позиция по идентификатору элемент рамы
self.driver.switch_to.frame(frame) # Перейти к этому кадру
def move_search_btn(self):
'''
Наведите курсор мыши на список объявлений о тендерах
'''
search_btn = self.driver.find_elements_by_class_name(
"ewb-right-tab")[3]
# Разверните текущую страницу, чтобы переместить указатель мыши на этот элемент.
self.driver.maximize_window()
webdriver.common.action_chains.ActionChains(
self.driver).move_to_element(search_btn).perform()
time.sleep(3) # После нажатия кнопки поиска нужно дождаться обновления рамкаданных кадров.
# Прокрутите страницу до конца, чтобы избежать исключений при извлечении элементов.
self.driver.execute_script('scrollTo(0,1000)')
def get_list(self):
'''
Получите каждую часть информации на странице списка проектов одну за другой.
'''
project_list = self.driver.find_elements_by_xpath(
"//ul[contains(@class,'ewb-right-item')]//a")
# Определите массив для временного хранения всех URL-адресов этой страницы.
temp_url_list = []
# Перейти на страницу сведений о проекте
for item in project_list:
name = item.get_attribute("textContent")
if (name.find("Дизайн") > 0) and (name.find("Дорога") > 0): # Фильтр по названию проекта
temp_url_list.append(item.get_attribute('href'))
print(f"Получить {len(temp_url_list)} действительных элементов на странице {self.counter+1}.")
if len(temp_url_list) > 0: # Прыжок будет выполнен только тогда, когда список получит действительные данные.
for url in temp_url_list:
self.blank_in_detail(url)
return True # После получения действительных данных на этой странице вам необходимо перейти на страницу сведений. Если вы вернетесь назад, вам необходимо повторно войти в Iframeramka.
else:
return False
def blank_in_detail(self, url):
'''
Открыть новое подробное окно для элемента в списке проектов.
'''
# Откройте новую вкладку, выполнив js
js = "window.open('"+url+"');"
self.driver.execute_script(js)
windows = self.driver.window_handles # 1. Получить все текущие окна
self.driver.switch_to.window(windows[1]) # 2. Переключение на основе индекса окна
self.get_detail_info(url)
self.driver.close()
self.driver.switch_to.window(windows[0]) # Хотя окно можно закрыть, да все равно придется прыгать вручную
def get_detail_info(self, url):
'''
Получите информацию на странице сведений о проекте.
'''
temp_dict = {} # Интегрируйте словарь для этого проекта
temp_dict['url'] = url # URL веб-страницы проекта
temp_dict['name'] = self.driver.find_element_by_id(
'showtitle').text # Название проекта
temp_dict['legal_person'] = self.driver.find_element_by_xpath(
"//*[@id='container']//tbody/tr[2]/td[2]").get_attribute("innerHTML") # Юридическое лицо проекта
temp_dict['time'] = self.driver.find_element_by_xpath(
"//tbody/tr[5]/td[4]").get_attribute("innerHTML") # время
print(temp_dict['legal_person'], temp_dict['time'])
main_text = self.driver.find_elements_by_xpath(
"//div[contains(@class, 'ewb-info-bd')]")[3]
item_info = self.handle_string(
main_text.get_attribute('textContent')) # Получить информацию о торгах
# Улучшить информацию о проекте
temp_dict['bid_price'] = item_info[0]
temp_dict['bidder'] = item_info[1]
temp_dict['committee'] = item_info[2]
temp_dict['abandon'] = item_info[3]
print(temp_dict)
# писатьданные json_data = json.dumps(temp_dict, ensure_ascii=False)+',\n' # форматирование json
self.file.write(json_data) # Напишите jsonданные
@staticmethod
def handle_string(string):
'''
Отфильтруйте информацию о победившей ставке на странице сведений о проекте.
'''
string = re.sub(' ', '', string) # Удалить все пробелы (переносы строк не удаляются и могут использоваться как разделители)
string = re.sub(':', ':', string) # Заменить китайские символы
string = "".join(
[s for s in string.splitlines(True) if s.strip()]) # Удалить все пустые строки
# print(string)
if (string.find('метка потока') > 0) or (string.find('Информации пока нет') > 0) or (string.find('сдаваться') > 0):
# Расход по проекту или нет информации
return '', '', '', True
else:
bid_price = bidder = committee = ''
try:
# Проект имеет информацию о победивших торгах
if re.search(r'(:?)([\d+\.]+)(\)?)Юань', string): # Найти сумму выигрышной ставки
bid_price = re.search(
r'(:?)([\d+\.]+)(\)?)Юань', string).group(2)
elif re.search(r'Сумма выигрышной ставки(.*?)([\d+\.]+)(\)?)', string): # Найти сумму выигрышной ставки
bid_price = re.search(
r'Сумма выигрышной ставки(.*?)([\d+\.]+)(\)?)', string).group(2)
elif re.search('Выигрышная цена за единицу: (.+)\n', string):
bid_price = re.search('Выигрышная цена за единицу: (.+)\n', string).group(1)
elif re.search("Доля выигрышных ставок: (.+)\n", string):
bid_price = re.search('Выигрышная цена за единицу: (.+)\n', string).group(1)
else:
pass
if re.search('Имя объекта:(.+)\n', string): # Найдите победителя торгов
bidder = re.search('Имя объекта:(.+)\n', string).group(1)
if re.search('Список участников:(.+)\n', string): # Найдите победителя торгов
committee = re.search('Список участников:(.+)\n', string).group(1)
except:
print("Не удалось получить информацию о проекте!")
finally:
# Возврат к цене торгов, победитель торгов, комиссия по оценке заявок
return bid_price, bidder, committee, False
def click_next_page(self):
'''
Нажмите, чтобы перейти на следующую страницу
'''
try:
next_page_url = self.driver.find_elements_by_class_name(
"wb-page-next")[1]
except:
print("Не удалось получить следующую страницу! (или просканированы все данные.)")
else:
self.counter += 1
print(f"Сканирование страницы {self.counter} завершено, выполняется переход к следующей странице...")
next_page_url.click()
time.sleep(3) # Ожидание реконструкции страницы Iframeрамка
def __del__(self):
'''
Сохраните файл при уничтожении объекта (чтобы предотвратить аварийное завершение программы)
'''
self.file.close() # сохранить файл
self.driver.quit() # Выход Браузер
if __name__ == "__main__":
# программа Вход my_spider = BiddingInfo()
my_spider.run()
----- END -----