我的抓取功能有问题。
在这个项目中,我有一个sqlite3数据库,该数据库包含指向唱片评论的链接。我创建了一个scraper.py文件,其中包含以下两种方法:
from bs4 import BeautifulSoup
import requests
def take_source(url):
if 'http://' or 'https://' in url:
source = requests.get(url).text
return source
else:
print("Invalid URL")
def extract_corpus(source):
soup = BeautifulSoup(source, "html.parser")
soup.prettify().encode('cp1252', errors='ignore')
corpus = []
for e in soup.select("p"):
corpus.append(e.text)
return corpus
我在名为embedding.py的文件中调用extract_corpus方法, 在此文件中,我创建了一个与sqlite3数据库的连接,并将数据放入Pandas Dataframe中。 我想将所有链接的内容存储在一个csv文件中。我的embedding.py文件包含:
import sqlite3
import pandas as pd
import scraper
import csv
#create connection with sqlite db
con = sqlite3.connect("database.sqlite")
#creating a pandas data frame
query = pd.read_sql_query("SELECT url, artist, title FROM reviews;", con)
#populating data frame with urls
df = pd.DataFrame(query, columns=['url', 'artist', 'title'])
#preparing the .csv file for storing the reviews
with open('reviews.csv', 'w') as csvfile:
fieldnames = ['title', 'artist', 'review']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
def append_csv(tit,art,rev):
with open('reviews.csv','a') as csv_f:
writer = csv.DictWriter(csv_f, fieldnames=fieldnames)
writer.writerow({'title': tit, 'artist':art,'review':rev})
for i, row in df.iterrows():
album = (str(row.__getitem__('title')))
artist = (str(row.__getitem__('artist')))
review = str(scraper.extract_corpus(scraper.take_source(str(row.__getitem__('url')))))
append_csv(album,artist,review)
当我运行此文件时,它适用于初始链接组,然后中断返回标题中的错误。这是错误:
回溯(最近通话最近):文件 “ C:/Users/kikko/PycharmProjects/SongsBot/embedding.py”,第59行,在 append_csv(专辑,艺术家,评论)文件“ C:/Users/kikko/PycharmProjects/SongsBot/embedding.py”,第52行,在 append_csv writer.writerow({'title':tit,'artist':art,'review':rev})文件“ C:\ Users \ kikko \ AppData \ Local \ Programs \ Python \ Python37-32 \ lib \ csv.py ”, 155行,在writerow中 返回self.writer.writerow(self._dict_to_list(rowdict))文件“ C:\ Users \ kikko \ AppData \ Local \ Programs \ Python \ Python37-32 \ lib \ encodings \ cp1252.py”, 第19行,编码 返回codecs.charmap_encode(input,self.errors,encoding_table)[0] UnicodeEncodeError:“ charmap”编解码器无法在其中编码字符“ \ u011f” 位置1087:字符映射到
很遗憾,我找不到错误。 多谢您的协助。 预先谢谢你。
答案 0 :(得分:0)
似乎您在这里有多种误解。
soup.prettify().encode('cp1252', errors='ignore')
这没什么用:创建一个表示HTML源的字符串(用.prettify
,将其编码为字节(.encode
),然后对结果对象不执行任何操作。 soup
未经修改。
幸运的是,无论如何,您现在都不需要或不想对编码做任何事情。但是最好完全删除此行,以免误导自己。
for e in soup.select("p"):
corpus.append(e.text)
return corpus
您将生成并返回一个字符串列表,稍后您将尝试使用str
将其转换为字符串。结果将显示列表的表示形式:即,它将包含在[]
中,并用逗号分隔每个字符串的项目和引号以及转义序列。这可能不是您想要的。
我假设您想将字符串连接在一起,例如'\n'.join(corpus)
。但是,这样的多行数据不适合存储在CSV中。 (转义的列表表示形式也很难存储在CSV中。您可能应该更多地考虑如何格式化数据。)
review = str(scraper.extract_corpus(scraper.take_source(str(row.__getitem__('url')))))
首先,您不应直接调用__getitem__
之类的双下划线方法。我知道它们在文档中是这样写的。那只是Python一般如何工作的产物。您应该这样使用__getitem__
:row['url']
。
您应该期望结果已经是字符串,因此内部str
调用是无用的。然后,您使用take_source
,它会出现以下错误:
if 'http://' or 'https://' in url:
此does not do what you want;该功能将始终认为该URL是“有效”。
无论如何,一旦您设法extract_corpus
并从中强行产生一个字符串,就会出现您要询问的实际问题:
with open('reviews.csv','a') as csv_f:
您不能简单地以cp1252编码将任何任意字符串写入文件(您知道这是正在使用的字符串,因为在堆栈跟踪中提到了cp1252.py
;这是平台的默认设置) 。 这是您应该指定文件编码的地方。例如,您可以指定应使用encoding='utf-8'
编写文件,该文件可以处理任何字符串。 (您出于其他任何目的再次打开文件时,也需要明确指定此名称。)
如果您坚持手动进行编码,那么您将需要.encode
.write
进行文件编码。但是,由于.encode
会产生原始编码的字节,因此您将需要以二进制模式打开文件(例如'ab'
),这也意味着您必须自己处理通用换行编码。这不是一件令人愉快的任务。请根据设计用途来使用该库。
当要正确处理文本编码等问题时,您 不能 仅通过尝试在出现错误时进行修复,就编写出质量不错的正确代码,在网络上搜索每个错误或通过强制转换使类型错误消失。您 必须真正了解正在发生的事情 。我不能太强调这一点。请启动here,然后再阅读here。从头到尾阅读这两个书,目的是了解他们在说什么,而不是试图解决任何特定问题。