Добрый день, добавил в код парсера функции для сохранения фотографий, теперь рядом с csv файлом сохраняется папка с фотографиями из объявлений. Для каждого объявления своя папка. В планах добавить изменений прокси(proxy) сервера и юзер агента(useragent), для того чтобы не нарваться на бан.
import requests
from bs4 import BeautifulSoup
from time import sleep
from selenium import webdriver
import urllib.request
import csv
import os
#функция для получения html
def get_html(url):
r = requests.get(url)
return r.text
#функция подсчета количества страниц
#используем библиотеку BeautifulSoup для поиска html тегов на странице
#
def get_total_pages(html):
soup = BeautifulSoup(html, 'lxml') # определяем объект soup
divs = soup.find('nav', class_='paginator-public') # находим на странице первый объект nav с именем класса paginator-public
pages = divs.find_all('a', class_='paginator-page-btn')[-2].get('href') # находим на странице все теги "a" с именем класса paginator-page-btn, из них выбираем элемент с индексом [-2] это будет последняя страница
print(pages)
total_pages = pages.split('page=')[1].split('&')[0] # из полученной ссылки делаем сплит и выбираем значение между знаком "=" и "&"
return int(total_pages) #возвращаем полученное значение
# return 2
# находим количество фотографий и формируем ссылки на фотографии
def find_all_photo_urls(html):
soup = BeautifulSoup(html, 'lxml') # определяем объект soup
divs = soup.find('div', class_='gallary__container')
# проверяем наличие фотографий, если в объявлении нет фотографий то возвращаем 100
if (len(divs.text))==1:
photo_kol=100
return photo_kol
photo_kol = len(divs.find_all('li')) # считаем количество фотографий
if photo_kol == 0:
photo_kol = 1
return photo_kol
print(photo_kol)
# получаем url фотографий
photo_url = divs.find_all('div', class_='gallary__small-item')
all_photo = [] # создаем список и передаем ему все ссылки на фотографии
for i in range(photo_kol):
all_photo.append(photo_url[i].get('data-photo-url'))
return all_photo
def get_file(url):
r = requests.get(url, stream=True)
return r
# задаем имя файла и создаем папку на компьютере
def get_name(url, folder):
name = url.split('/')[-1]
if not os.path.exists(folder):
os.makedirs(folder)
path = os.path.abspath(folder)
# print('get_name'+path)
return path + '\\' + name
# сохраняем фотографии
def save_image2(url, name):
urllib.request.urlretrieve(url, name)
#функция для записи csv файла
def write_csv(data):
with open('krisha.csv', 'a', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerow((data['title'],
data['price'],
data['etaj'],
data['square'],
data['address'],
data['description'],
data['url'],
data['telephone']))
#функция для получения телефонов
#так как на сайте скрыты телефоны, необходимо использовать дополнительный пакет selenium
#для имитации нажатия на ссылку с телефоном, для этого запускается браузер chrome в режиме
#"headless" т.е. без отображения окна
def get_phone(url):
options = webdriver.ChromeOptions()
options.add_argument('headless')
options.add_argument('window-size=1200x600')
#driver = webdriver.Chrome('C:\\python37\\chromedriver_win32\\chromedriver.exe') # or Firefox() or smth else
driver = webdriver.Chrome(options=options) # определяем объект типа webdriver
driver.get(url) # передаем ему на вход url
link = driver.find_element_by_id('tm-telephone-body') # переменной link присваиваем ссылку, которая нам покажет телефон
link.click() # кликаем на ссылку
sleep(1) # делаем паузу в 1 секунду
tel = driver.find_element_by_class_name('offer__contacts-phones').text.strip() # присваиваем переменной tel показанные номера телефонов
driver.quit() # не забываем закрывать невидимый браузер
return tel # возвращаем телефон
# функция получения данных с сайта, используем библиотеку BeautifulSoup, она позволяет выполнять поиск по html тегам
#
def get_page_data(html):
soup = BeautifulSoup(html, 'lxml') # определяем объект soup
divs = soup.find('section', class_='a-list') # находим тег section с именем класса a-list
ads = divs.find_all('div', class_='a-card__inc') # в найденном объекте ищем все div с классом a-card__inc
# запускаем цикл по всем найденным полям, которые нас интересуют
# т.к. ссылка состоит 3-комнатная квартира, 79.4 м², 5/5 эт. я решил ее разделить на поля квартира, площадь, этаж
# далее выбираем цену, адрес и описание
#
for ad in ads:
try:
div = ad.find('a', class_='a-card__title').text
kv = div.split(",")[0]
except:
kv = ''
try:
div = ad.find('a', class_='a-card__title').text
square = div.split(",")[1]
except:
square = ''
try:
div = ad.find('a', class_='a-card__title').text
etaj = div.split(",")[2]
except:
etaj = ''
try:
price = ad.find('div', class_='a-card__price').text.strip()
except:
price = ''
try:
address = ad.find('div', class_='a-card__subtitle').text.strip()
except:
address = ''
try:
descr = ad.find('div', class_='a-card__text-preview').text.strip()
except:
descr = ''
try:
div = ad.find('div', class_='a-card__header-left')
url = "https://krisha.kz" + div.find('a').get('href')
#tel = ''
except:
url = ''
#tel = ''
# парсим урл и присваиваем значение переменной folder , это и будет именем папки с фото
folder = url.split('/')[-1]
urls = find_all_photo_urls(get_html(url)) # вызываем функцию поиска урлов всех фотографий
# в функции выше мы возвращали значение 100, тут проверяем, если 100 значит фотографий в объявлении нет, иначе фотки есть - сохраняем их
if urls == 100:
print ("Фотографий в объявлении нет!")
else:
for url2 in urls:
save_image2(url2, get_name(url2, folder))
tel1 = get_phone(url) # тут вызываем функцию выборки телефонов
# определяем кортеж из наших полей и передаем его функции write_csv
data = {'title':kv,
'price':price,
'etaj':etaj,
'square':square,
'address':address,
'description':descr,
'url':url,
'telephone':tel1}
write_csv(data)
# основная функция
# базовый url для Астаны имеет вид https://krisha.kz/prodazha/kvartiry/astana/
# к нему добавляется запрос query_part и еще дальше идет блок со страницами page_part
#
def main():
#url = 'https://krisha.kz/prodazha/kvartiry/astana/?das[live.rooms]=1'
# тут передаем основной урл для парсинга
url_gen = ('https://krisha.kz/prodazha/kvartiry/astana-almatinskij/?das[flat.floor][from]=1&das[flat.floor][to]=1&das[live.rooms]=1&sort_by=price-asc')
total_pages = get_total_pages(get_html(url_gen))
for i in range(1, total_pages):
# url_gen = base_url + query_part + page_part + str(i)
html = get_html(url_gen)
get_page_data(html)
#блок main
if __name__ == '__main__':
main()
Комментариев нет:
Отправить комментарий