Проблема с кодировкой при записи в csv python
Понимаю что вопрос нубский, а код овно. Но не могу разобраться с кодировкой при записи в csv. Python 3.7 Пишу из под винды 10 и pycharm
Ниже код и приме того как записывается . Помогите разобраться. Спасибо
import requests
from bs4 import BeautifulSoup
import lxml
import csv
url = 'https://www.avito.ru/krasnodar/kvartiry/prodam/vtorichka-ASgBAgICAkSSA8YQ5geMUg'
headers = {'accept': '*/*',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36'
}
flats = {
'title': None,
'price': None,
'address': None,
'href': None
}
# Создаем CSV файл с заголовками для дальнейшей записи в него полученных параметров
with open('flats.csv', 'w', newline='') as file:
writer = csv.writer(file, delimiter=';')
writer.writerow(['Заголовок', 'Цена', 'Адрес', 'Ссылка'])
#
req = requests.get(url, headers=headers)
src = req.text
with open('index_1.html', 'w', encoding='utf-8') as file:
file.write(src)
print('Обработка и скачивание страницы 1 завершено')
for i in range(2, 11):
req = requests.get(f'{url}' + '?p=' + str(i))
src = req.text
with open(f'index_{i}.html', 'w', encoding='utf-8') as file:
file.write(src)
print(f'Обработка и скачивание страницы {i} завершено')
print('Запускаю обратботку информации на скачаных страницах')
for i in range(1, 11):
with open(f'index_{i}.html', 'r', encoding='utf8') as file:
src = file.read()
soup = BeautifulSoup(src, 'lxml')
cards_offers = soup.find('div', {'data-marker': 'catalog-serp'})
cards = cards_offers.find_all('div', class_="iva-item-content-rejJg")
for element in cards:
# Достаем заголовок
title_res = element.find('div', class_="iva-item-titleStep-pdebR").text
title = str(title_res).replace(' ', '')
# Достаем ссылку на объявление
href_res = element.find('a').get('href')
href = str('https://www.avito.ru' + href_res)
# Достаем цену за квартиру
price = str(element.find('span', class_="price-text-_YGDY text-text-LurtD text-size-s-BxGpL").text.replace('₽',
'').replace(
' ', ''))
address = str(element.find('span', class_="geo-address-fhHd0 text-text-LurtD text-size-s-BxGpL").text)
flats.update({'title': title,
'price': price,
'address': address,
'href': href
})
with open('flats.csv', 'a', newline='', encoding='utf-8') as file:
writer = csv.writer(file, delimiter=';')
writer.writerow([flats['title'], flats['price'], flats['address'], flats['href']])
Ответы (1 шт):
Собственно можно было в коментариях просто написать:
with open('flats.csv', 'w', encoding='utf-8-sig') as fileНо решил немного подшаманить ваш код
pip install bs4 tqdm fake-useragent requests --upgrade
Вариант для python3.7
import csv
import re
from unicodedata import normalize
from bs4 import BeautifulSoup as Soup
from bs4.element import Tag
from fake_useragent import UserAgent
from requests import Session
from pathlib import Path
from tqdm import tqdm
ua = UserAgent()
s = Session()
s.headers.update(
{
'User-Agent': ua.firefox
}
)
pages_for_fetch = 5
sheet_header = ['Заголовок', 'Цена', 'Адрес', 'Ссылка']
def pages_qty(pages_tag: Tag):
return max(
[
int(item.get_text(strip=True))
for item in pages_tag.find_all(
'span',
{'data-marker': re.compile(r'\(\d+\)$')}
)
] or [1]
)
base_url = 'https://www.avito.ru'
url = base_url + '/krasnodar/kvartiry/prodam/vtorichka-ASgBAgICAkSSA8YQ5geMUg?p=%s'
def snippet(ad_tag: Tag):
price = None
href = None
address = None
title = None
tag = ad_tag.find('span', class_=re.compile(r'^geo-address-.+'))
if tag:
address = tag.get_text(strip=True)
price_tg = ad_tag.find('span', class_=re.compile(r'^price-text-.*'))
if price_tg:
span = price_tg.find('span')
if span:
span.replace_with('')
price = normalize('NFKC', price_tg.get_text(strip=True)).replace(' ', '')
tag = ad_tag.find('h3', class_=re.compile(r'^title-root-.*'))
if tag:
title = tag.get_text(strip=True)
a = tag.find_parent('a')
if a:
href = base_url + a.get('href')
return dict(
zip(
sheet_header,
(
normalize('NFKC', title),
price,
normalize('NFKC', address),
href
)
)
)
def page(page_number: int):
response = s.get(
url % page_number
)
soup = Soup(response.content, 'html.parser')
# print(f'Обработка и скачивание страницы {page_number} завершено')
# Если прям очень хочется сохранять страницы, то можно так
Path(__file__).parent.joinpath(f'page_{page_number}.html').write_text(soup.prettify(), encoding='utf-8')
return map(snippet, soup.find_all('div', class_=re.compile(r'^iva-item-body-.+'))), pages_qty(soup)
pg, qty = page(1)
total_pages = min(pages_for_fetch, qty)
ads = [*pg] + [
elem for item, _ in [
page(num) for num in tqdm(range(2, total_pages + 1), initial=1, total=total_pages)
] for elem in item
]
with open('flats.csv', 'w', encoding='utf-8-sig') as file:
writer = csv.DictWriter(
file,
sheet_header,
delimiter=',',
dialect='unix'
)
writer.writeheader()
writer.writerows(ads)
Для 3.8 и выше:
import csv
import re
from unicodedata import normalize
from bs4 import BeautifulSoup as Soup
from bs4.element import Tag
from fake_useragent import UserAgent
from requests import Session
ua = UserAgent()
s = Session()
s.headers.update(
{
'User-Agent': ua.firefox
}
)
pages_for_fetch = 5
sheet_header = ['Заголовок', 'Цена', 'Адрес', 'Ссылка']
def pages_qty(pages_tag: Tag):
return max(
[
int(item.get_text(strip=True))
for item in pages_tag.find_all(
'span',
{'data-marker': re.compile(r'\(\d+\)$')}
)
] or [1]
)
base_url = 'https://www.avito.ru'
url = base_url + '/krasnodar/kvartiry/prodam/vtorichka-ASgBAgICAkSSA8YQ5geMUg?p=%s'
def snippet(ad_tag: Tag):
price = None
href = None
address = tag.get_text(strip=True) if (
tag := ad_tag.find('span', class_=re.compile(r'^geo-address-.+'))
) else None
if price_tg := ad_tag.find('span', class_=re.compile(r'^price-text-.*')):
if span := price_tg.find('span'):
span.replace_with('')
price = normalize('NFKC', price_tg.get_text(strip=True)).replace(' ', '')
title = tag.get_text(strip=True) if (
tag := ad_tag.find('h3', class_=re.compile(r'^title-root-.*'))
) else None
if tag:
href = base_url + a.get('href') if (
a := tag.find_parent('a')
) else None
return dict(
zip(
sheet_header,
(
normalize('NFKC', title),
price,
normalize('NFKC', address),
href
)
)
)
def page(page_number: int):
response = s.get(
url % page_number
)
soup = Soup(response.content, 'html.parser')
return map(snippet, soup.find_all('div', class_=re.compile(r'^iva-item-body-.+'))), pages_qty(soup)
pg, qty = page(1)
ads = [*pg] + [
elem for item, _ in [
page(num) for num in range(2, min(pages_for_fetch, qty) + 1)
] for elem in item
]
with open('flats.csv', 'w', encoding='utf-8-sig') as file:
writer = csv.DictWriter(
file,
sheet_header,
delimiter=',',
dialect='unix'
)
writer.writeheader()
writer.writerows(ads)
P.S.
pages_for_fetchпредназначена для того, чтобы указать количество страниц для парсинга
P.P.S И еще один совет. Не используйте
excelдля работы сcsvда и вообще с любыми файлами созданными не вexcel. Велика вероятность того, чтоExcelсломает эти данные. (За исключением тех случаев когда данные подтягиваются черезPowerQuery). Используйте, к примеру,ClacизLibreOffice. Намного корректней работает.
