Помогите решить проблему с кодировкой в python при записи в файл csv
написал простенький парсер. Сохраняет данные в scv формат, кодировка обязательно cp1251 так как эти данные потом импортируются на сайт, а там принимает только в этой кодировке. Подскажите почему вылетает ошибка? причем вылетает рандомно, может пропарсить несколько страниц и выдать ошибку, а может и не одной не пропарсить и выдать ошибку:
Traceback (most recent call last):
File "C:\Users\Manager\PycharmProjects\parser.py\main.py", line 124, in <module>
parser()
File "C:\Users\Manager\PycharmProjects\parser.py\main.py", line 118, in parser
save_doc(info_list, CSV)
File "C:\Users\Manager\PycharmProjects\parser.py\main.py", line 92, in save_doc
writer.writerow(['', item['article'], item['title'], item['price'], '', 'СКАНЕРЫ ШТРИХ-КОДА',
File "C:\Program Files\Python39\lib\encodings\cp1251.py", line 19, in encode
return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\xba' in position 532: character maps to <undefined>
вот код, понимаю что он корявый, но это моя первая полноценная программа, прошу понимания.
import csv
import re
from tqdm import tqdm
import requests
from bs4 import BeautifulSoup
REG = r'([A-Z0-9]{3,}-[\w]{2}-[\w0-9]{3,})|([A-Z0-9]{3,}-[\w0-9]{3,})|([A-Z0-9]{3,}-[\w0-9]{2})'
HOST = 'https://interid.ru'
# URL = 'https://interid.ru/scanery-shtrih-kodov'
# CSV = 'scanner.csv'
# PARAMS = {'manufacturer_id': 13, 'param890': 648}
HEADERS = {
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,'
'application/signed-exchange;v=b3;q=0.9',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/87.0.4280.88 Safari/537.36 '
}
def get_html(url, params=''):
req = requests.get(url, headers=HEADERS, params=params)
return req
# получаем url конкретной страницы продукта
def get_url(html):
soup = BeautifulSoup(html, 'lxml')
url = soup.find_all('div', class_='product')
urls = []
for i in url:
urls.append({
'url_page': HOST + i.find('div', class_='c-title').find('a').get('href')
})
return urls
# Собираем нужные данные с конкретной страницы продукта
def parser_page_product(html_page):
soup = BeautifulSoup(html_page, 'lxml')
info_product = soup.find('div', class_='c-contents')
info_product.encode('cp1251')
params = []
params_list = soup.find_all('div', class_='param')
for i in params_list:
params.append({
i.find('div', class_='param-name').get_text(strip=True): i.find('div', class_='param-value').get_text(
strip=True)
})
table_html = ''
for i in params:
for key, value in i.items():
table_html = table_html + ('<tr><td>' + str(key) + '</td><td>' + str(value) + '</td></tr>')
info_product_list = [{
# название
'title': info_product.find('h1', class_='c-header-product-title').find('span').get_text(strip=True),
# артикул, полчаем через регулярное выражение
'article': re.search(REG, info_product.find('h1', class_='c-header-product-title').find('span').get_text(
strip=True))[0],
# цена
'price': info_product.find('div', class_='price').find('span', class_='price-value').get_text(strip=True),
# ссылка на изображение
'url_img': info_product.find('a', class_='c-images-list-item is-active').get('href'),
# короткое описание
'short_desc': info_product.find('div', class_='c-description').find('p').get_text(strip=True),
# характеристики
'params': '<table style="width: 65%;" border="1" cellpadding="10" cellspacing="0"><tbody>' + table_html +
'</tbody></table>'
}]
return info_product_list
# сохраняем данные в файл .csv
def save_doc(items, path):
description = ' Заказ и доставка в течении 3 дней. Подбор, консультация, демо зал на Таманской.'
title = ' купить в Краснодаре, оптимальная цена в магазине Штрих-Маркет'
with open(path, 'w', encoding='cp1251', newline='') as file:
writer = csv.writer(file, delimiter=';')
writer.writerow(['id', 'Артикул *', 'Название товара *', 'Стоимость товара *', 'Стоимость со скидкой',
'Раздел товара *', 'Товар в наличии *', 'Поставка под заказ *', 'Срок поставки (дни) *',
'Краткий текст', 'Текст полностью', 'Заголовок страницы (title)',
'Описание страницы (description)',
'Ключевые слова страницы (keywords)', 'ЧПУ страницы (slug)', 'С этим товаром покупают',
'Рекламные метки', 'Показывать на сайте *', 'Удалить *', 'Ед. измерения', 'Вес',
'Габариты, см',
'НДС', 'Передавать в Яндекс.Маркет'])
for item in items:
writer.writerow(['', item['article'], item['title'], item['price'], '', 'СКАНЕРЫ ШТРИХ-КОДА',
'0', '1', '15', item['short_desc'],
item['params'], item['title'] + title, item['short_desc'] + description, item['title'], '',
'', '', '1', '0', 'шт', '', '', '', '1'])
# основной метод
def parser():
URL = 'https://interid.ru/scanery-shtrih-kodov'
CSV = 'scanner.csv'
PARAMS = {'manufacturer_id': 13, 'param890': 648}
info_list = []
html = get_html(URL, params=PARAMS)
if html.status_code == 200: # проверка статуса ответа сайта
print('Сайт доступен!\nПарсинг запущен:')
page = int(input('Укажите кол-во страниц для парсинга => ').strip())
# проходим по страницам каталога и получаем ссылку на отдельную страницу каждого товара
for page in range(1, page + 1):
html = get_html(URL + '/page/' + str(page), params=PARAMS)
print(f'Страница => {page}')
# перебираем словарь; добавляем прогрессбар
for i in tqdm(get_url(html.text)):
for key in i:
html = get_html(i[key])
info_list.extend(parser_page_product(html.text))
save_doc(info_list, CSV)
print('Парсинг окончен. Данные сохранены в файле ' + CSV)
else:
print('Ошибка! Неверная ссылка или сайт недоступен.')
parser()
Ответы (1 шт):
Автор решения: Voko
→ Ссылка
Нужно указать кодировку сохранения для CSV-файла и задать режим обработки символов, не входящих в множество кодировки cp1251:
def save_doc(items, path):
.....
with open(path, 'w', newline='', encoding='cp1251', errors="ignore") as file:
....