scrapy 递归抓取抓取的中文结果乱码,请问如何解决

python中文字符编码decode,encode以及乱码解决总结 - 为程序员服务
为程序员服务
python中文字符编码decode,encode以及乱码解决总结
字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。
decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode('gb2312'),表示将gb2312编码的字符串str1转换成unicode编码。
encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode('gb2312'),表示将unicode编码的字符串str2转换成gb2312编码。
因此,转码的时候一定要先搞明白,字符串str是什么编码,然后decode成unicode,然后再encode成其他编码
(与代码本身的编码是一致的!)
我的eclipse里面代码为utf-8编码的。然后我这样写代码
s=s.decode('gb2312').encode('utf-8')
UnicodeDecodeError: 'gb2312' codec can't decode bytes in position 2-3: illegal multibyte sequence
原因:因为我的文件为UTF-8编码的。所以你想用gb2312将其转成unicode是不可能的。
所以正确的写法应当是:
s=s.decode('utf-8').encode('utf-8') 要用UTF-8来做编码
发现打印出来的是乱码那只能说明一件事情就是我的eclipse控制台是GB2312的编码!
如何获得系统的默认编码?
#!/usr/bin/env python
#coding=utf-8
import sys
print sys.getdefaultencoding()
该段程序在英文WindowsXP上输出为:ascii 。我发现我的linux上面也是ascii编码。所以我想打印出来看到的乱码是正常的。因为我其实是utf-8编码的。
在某些IDE中,字符串的输出总是出现乱码,甚至错误,其实是由于IDE的结果输出控制台自身不能显示字符串的编码,而不是程序本身的问题。(是的。我的eclipse控制台就是gb2312的编码所以我文件保存为utf-8的时候然后再通过打印是乱码了!)
1、读文件命令肯定是:
myfile = codecs.open("c.html","r","utf-8") 因为我用gb2312来读的话报错
心得:检查一个字符串是什么编码只需要看一下decode 如果用gb2312来decode没报错的话就表示是gb2312
如果用utf-8来decode没有报错的话就表示是utf-8
现在遇到一个问题就是
myfile = codecs.open(&c.html&,&r&,&utf-8&)
str = myfile.read()
content = str.replace(&\n&,& &)
content = content.encode('utf-8')
print content
myfile = codecs.open(&c.html&,&r&,&utf-8&)
str = myfile.read()
content = str.replace(&\n&,& &)
content = content.encode('gb2312')
print content
报错:UnicodeEncodeError: 'gb2312' codec can't encode character u'\u2014' in position 12628
myfile = codecs.open(&d.html&,&r&,&utf-8&)
str = myfile.read()
content = str.replace(&\n&,& &)
content = content.encode('gb2312')
print content
myfile = codecs.open(&d.html&,&r&,&utf-8&)
str = myfile.read()
content = str.replace(&\n&,& &)
content = content.encode('utf-8')
print content
结论:我想是c.html页面里面 存在某些 特殊字符 只支持utf-8编码。而不支持gb2312的编码!
而d.html没有这种特殊字符。这也就解释了为什么
有的文件并没有发生我们想像中的问题!
所以我感觉打开文件肯定是用utf-8来读取得到一个unicode编码值!
然后对其做utf-8的编码处理。因为如果你做gb2312处理的话就会报错了!
我看了一下我的正则表达式发现如果用gb2312做解码处理的话一样会报错。所以断定肯定是utf-8编码了!
regex3 = regex3.decode('utf-8')
print type(regex3)
#返回为unicode码了!
print regex3
#居然打印为正常的中文显示了 奇怪
尝试解决办法:
1、全部用unicode处理
即正则我用regex3 = regex3.decode('utf-8') 将其处理成 unicode编码了。然后内容也print type(content) 也是unicode编码。结果还是不行!
难道是我的linux终端的编码引起的吗?我看了一下locale 发现是GBK的终端的。即只有GBK编码才能显示出来为中文的!于是我将
regex3 = regex3.decode('utf-8').encode('gb2312') 编码成gb2312结果可以显示中文!
OK。我又将我的内容也一起弄成GB2312
content = content.encode('gb2312','ignore')
print content
也可以成功打印出来中文。
我想这个时候应该没有什么问题了吧。结果一用正则又死掉了。昏死!!!!!!!
换另外一个好的文件测试下看看:换了之后发现没死而且成功了!
所以我觉得:肯定是这个文件里面的某些内容与正则匹配出现了冲突!导致的!
继续跟踪:
出现如下的情况
myfile = codecs.open(&01.htm&,&r&,&utf-8&,&ignore&)
str = myfile.read()
content = str.replace(&\n&,& &)
print type(content)
#发现是unicode码
regex3 = 'class=wpcpsCSS&([^&]+)(?:.*?wpcppb_CSS& ([0-9]+) &/span&)?.*?(?:.*?(已被关闭))?.*?([0-9]+)个回答.*?([0-9]+)次浏览.*?(?:&div class=wpcptfCSS&.*?user\?userid=([0-9]+).*?&(.*?)&/a& &/div&.*?)?(?:user\?userid=([0-9]+)&)? class=&wpfitCSS[^&]+&&([^&]+).*?class=wpcptsCSS&([^&]+).*?([0-9.]{9,}\*).*?class=wpcpdCSS&(.*?)&/div& &div class=wpcpfCSS&'
content = content.encode('utf-8')
pile(regex3)
results = p.findall(content)
没有什么问题可以成功出来结果。但是我
将content = content.encode('gb2312') 的话就发现 死掉了!
说明我的内容content与我的正则的编码其实是不一样的!
我现在将我的正则也调成gb2312来测试。结果发现可以出来。而且我的结果
results = p.findall(content)
for ele in results:
print ele[0],ele[1],ele[2],ele[3],ele[4],ele[5],ele[6],ele[7],ele[8],ele[9],ele[10]
在eclipse(默认为gb2312)下面也是没有问题的了!~
所以我想:如果content是GBK那正则的内容也应当是GBK 即两者的编码一定要保持一致!否则就会出现死掉程序的情况!
现在我这样来处理 全部使用unicode编码处理
myfile = codecs.open(&right.html&,&r&)
str = myfile.read()
content = str.replace(&\n&,& &)
content = content.decode('utf-8','ignore')
#使用utf-8解码出来
都使用unicode编码吧
现在正则也用
regex3 = regex3.decode('utf-8','ignore') 使用utf-8搞成unicode编码
OK现在再来测试!
解决正则出现中文的BUG结论:
1、打开文件
myfile = codecs.open("right.html","r")
不需要设置其编码的!
设置编码格式
str = myfile.read()
content = str.replace(&\n&,& &)
content = content.decode('utf-8','ignore')
#使用utf-8解码成unicode格式
regex3 = regex3.decode('utf-8','ignore')
#正则也统一使用utf-8解码成unicode格式
然后就可以
pile(regex3)
results = p.findall(content)
调用正则了!
您可能的代码
相关聚客文章
相关专栏文章scrapy抓取后怎么转码_百度知道
scrapy抓取后怎么转码
提问者采纳
貌似在数据前面加个u,可以正常显示,u'\u65b0\u5a18\ufe1\u606f',新娘街信息如果是windows的命令提示符里,print str.encode('gbk')转码就行了。
其他类似问题
为您推荐:
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁【转】python开源项目Scrapy抓取文件乱码解决
python开源项目Scrapy抓取文件乱码解决
scrapy进行页面抓去的时候,保存的文件出现乱码,经过分析是编码的原因,只需要把编码转换为utf-8即可,代码片段
import chardet
content_type = chardet.detect(html_content)
#print(content_type['encoding'])
content_type['encoding'] != "UTF-8":
& & html_content =
html_content.decode(content_type['encoding'])
html_content = html_content.encode("utf-8")
open(filename,"wb").write(html_content)
这样保存的文件就是中文了。
先把gb2312的编码转换为unicode编码
然后在把unicode编码转换为utf-8.
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。scrapy爬虫成长日记之将抓取内容写入mysql数据库-数据库-爱编程
scrapy爬虫成长日记之将抓取内容写入mysql数据库
  前面小试了一下scrapy抓取博客园的博客(您可在此查看),但是前面抓取的数据时保存为json格式的文本文件中的。这很显然不满足我们日常的实际应用,接下来看下如何将抓取的内容保存在常见的mysql数据库中吧。
  说明:所有的操作都是在&scrapy爬虫成长日记之创建工程-抽取数据-保存为json格式的数据&的基础上完成,如果您错过了这篇文章可以移步这里查看
  环境:mysql5.1.67-log
  操作步骤:
  1、检查python是否支持mysql
[root@bogon ~]# python
Python 2.7.10 (default, Jun
5 2015, 17:56:24)
[GCC 4.4.4
(Red Hat 4.4.4-13)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
&&& import MySQLdb
Traceback (most recent call last):
File "&stdin&", line 1, in &module&
ImportError: No module named MySQLdb
  如果出现:ImportError: No module named MySQLdb则说明python尚未支持mysql,需要手工安装,请参考步骤2;如果没有报错,请调到步骤3
  2、python安装mysql支持
[root@bogon ~]# pip install mysql-python
Collecting mysql-python
Downloading MySQL-python-1.2.5.zip (108kB)
100% |████████████████████████████████| 110kB 115kB/s
Building wheels for collected packages: mysql-python
Running setup.py bdist_wheel for mysql-python
Stored in directory: /root/.cache/pip/wheels/8c/0d/11/d654cad764b9dd2b9e1b0cd76c22f813c5851a
Successfully built mysql-python
Installing collected packages: mysql-python
Successfully installed mysql-python-1.2.5
  安装完以后再次运行步骤1,检查python是否已经支持mysql
  如果还有问题您可以尝试:LC_ALL=C pip install mysql-python  如果依然报错:error: Python.h: No such file or directory  您可以尝试先安装python-devel:
yum install python-devel
  3、创建数据库和表
CREATE DATABASE cnblogsdb DEFAULT CHARACTER SET utf8 COLLATE utf8_general_
CREATE TABLE `cnblogsinfo` (
`linkmd5id` char(32) NOT NULL COMMENT 'url md5编码id',
`title` text COMMENT '标题',
`description` text COMMENT '描述',
`link` text
COMMENT 'url链接',
`listUrl` text
COMMENT '分页url链接',
`updated` datetime DEFAULT NULL
COMMENT '最后更新时间',
PRIMARY KEY (`linkmd5id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
&  注意:
    a)、创建数据库的时候加上DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci,这样才不至于出现乱码。我就因为这个问题折腾了很久。
    b)、数据库表的编码为utf8
  4、设置mysql配置信息
  根据前面的文章()我们可以知道,最终scrapy是通过pipelines.py对抓取的结果进行处理的。很显然要保存到mysql数据库中的话,修改pipelines.py这个文件是在所难免的了。然而在进行mysql操作的时候,我们需要先连上数据库,这时候就设计到数据库连接字符串的问题了。我们可以直接写死在pipelines.py文件中,但是这样又不利于程序的维护,因此我们可以考虑将配置信息写在项目的配置文件settings.py中。
  settings.py中添加如下配置项
# start MySQL database configure setting
MYSQL_HOST = 'localhost'
MYSQL_DBNAME = 'cnblogsdb'
MYSQL_USER = 'root'
MYSQL_PASSWD = 'root'
# end of MySQL database configure setting
&  5、修改pipelines.py
  修改完的结果如下,需要注意的pipelines.py中定义了两个类。JsonWithEncodingCnblogsPipeline是写入json文件用的,而MySQLStoreCnblogsPipeline(需要记住,后面会用到哦!)才是写入数据库用的。
  MySQLStoreCnblogsPipeline类做的主要功能有
    a)、读取数据库配置文件,并生成数据库实例,主要通过类方法from_settings实现,
    b)、如果url不存在则直接写入,如果url存在则更新,通过自定义的方法_do_upinsert实现,
    c)、确保url唯一性的md5函数_get_linkmd5id 。
[root@bogon cnblogs]# more pipelines.py
# -*- coding: utf-8 -*-
# Define your item pipelines here
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
from scrapy import signals
import json
import codecs
from twisted.enterprise import adbapi
from datetime import datetime
from hashlib import md5
import MySQLdb
import MySQLdb.cursors
class JsonWithEncodingCnblogsPipeline(object):
def __init__(self):
self.file = codecs.open('cnblogs.json', 'w', encoding='utf-8')
def process_item(self, item, spider):
line = json.dumps(dict(item), ensure_ascii=False) + "\n"
self.file.write(line)
return item
def spider_closed(self, spider):
self.file.close()
class MySQLStoreCnblogsPipeline(object):
def __init__(self, dbpool):
self.dbpool = dbpool
@classmethod
def from_settings(cls, settings):
dbargs = dict(
host=settings['MYSQL_HOST'],
db=settings['MYSQL_DBNAME'],
user=settings['MYSQL_USER'],
passwd=settings['MYSQL_PASSWD'],
charset='utf8',
cursorclass = MySQLdb.cursors.DictCursor,
use_unicode= True,
dbpool = adbapi.ConnectionPool('MySQLdb', **dbargs)
return cls(dbpool)
#pipeline默认调用
def process_item(self, item, spider):
d = self.dbpool.runInteraction(self._do_upinsert, item, spider)
d.addErrback(self._handle_error, item, spider)
d.addBoth(lambda _: item)
#将每行更新或写入数据库中
def _do_upinsert(self, conn, item, spider):
linkmd5id = self._get_linkmd5id(item)
#print linkmd5id
now = datetime.utcnow().replace(microsecond=0).isoformat(' ')
conn.execute("""
select 1 from cnblogsinfo where linkmd5id = %s
""", (linkmd5id, ))
ret = conn.fetchone()
conn.execute("""
update cnblogsinfo set title = %s, description = %s, link = %s, listUrl = %s, updated = %s where linkmd5id = %s
""", (item['title'], item['desc'], item['link'], item['listUrl'], now, linkmd5id))
#print """
update cnblogsinfo set title = %s, description = %s, link = %s, listUrl = %s, updated = %s where linkmd5id = %s
#""", (item['title'], item['desc'], item['link'], item['listUrl'], now, linkmd5id)
conn.execute("""
insert into cnblogsinfo(linkmd5id, title, description, link, listUrl, updated)
values(%s, %s, %s, %s, %s, %s)
""", (linkmd5id, item['title'], item['desc'], item['link'], item['listUrl'], now))
#print """
insert into cnblogsinfo(linkmd5id, title, description, link, listUrl, updated)
values(%s, %s, %s, %s, %s, %s)
#""", (linkmd5id, item['title'], item['desc'], item['link'], item['listUrl'], now)
#获取url的md5编码
def _get_linkmd5id(self, item):
#url进行md5处理,为避免重复采集设计
return md5(item['link']).hexdigest()
def _handle_error(self, failue, item, spider):
log.err(failure)
&  6、启用MySQLStoreCnblogsPipeline类,让它工作起来
  修改setting.py配置文件,添加MySQLStoreCnblogsPipeline的支持
ITEM_PIPELINES = {
'cnblogs.pipelines.JsonWithEncodingCnblogsPipeline': 300,
'cnblogs.pipelines.MySQLStoreCnblogsPipeline': 300,
  至此,所有的需要修改的文件都修改好了,下面测试看结果如何。
  7、测试
[root@bogon cnblogs]# scrapy crawl CnblogsSpider
  查看数据库结果:
  至此,scrapy抓取网页内容写入数据库的功能就已经实现了。然而这个爬虫的功能还太弱小了,最基本的文件下载、分布式抓取等都功能都还不具备;同时也试想一下现在很多网站的反爬虫抓取的,万一碰到这样的网站我们要怎么处理呢?接下来的一段时间里我们来逐一解决这些问题吧。随便畅想一下,如果爬虫足够强,内容足够多;我们是不是可以打造一个属于自己的垂直搜索引擎呢?想想就兴奋,尽情YY去吧!!!
  最后源码更新至此:
版权所有 爱编程 (C) Copyright 2012. . All Rights Reserved.
闽ICP备号-3
微信扫一扫关注爱编程,每天为您推送一篇经典技术文章。scrapy 乱码 - CSDN博客
/blog/scrapy%E4%B8%AD%E6%96%87%E7%BC%96%E7%A0%81%E9%97%AE%E9%A2%98
http://www.pythonclub.org/python-basic/codec
————————————————————————————————————————————————————————————————
text = response.body
content_type = chardet.detect(text)
if content_type['encoding'] != 'UTF-8':
text = text.decode(content_type['encoding'])
text = text.encode('utf-8')
————————————————————————————————————————————————————————————————
& &Scrapy默认读取的内容ascii编码,而对中文不言而喻会出错,中文三大编码,后面的标准是前面标准的扩展。
& GBK & GB18030
& & Scrapy项目获取文本编码的方法有:
& & 1. 安装chardet第三方包,chardet.dectet()。
& & 2. import chardetect,好像其是封装chardet包。
& & 3. Scrapy返回内容 response.encoding属性。
& & 其中response.encoding返回可能不很准,如把gbk标成gb18030。而chardet或chardetect也不保证100%正确,且传给chardet.dectet()不是文件名,是字符串,若是大文件,则判断成本很高。
&&&&暂时不知真正高效的方法。
————————————————————————————————————————————————————————————————
为什么会报错“UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)”?本文就来研究一下这个问题。
字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。&
decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode('gb2312'),表示将gb2312编码的字符串str1转换成unicode编码。&
encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode('gb2312'),表示将unicode编码的字符串str2转换成gb2312编码。&
因此,转码的时候一定要先搞明白,字符串str是什么编码,然后decode成unicode,然后再encode成其他编码
代码中字符串的默认编码与代码文件本身的编码一致。&
如:s='中文'
如果是在utf8的文件中,该字符串就是utf8编码,如果是在gb2312的文件中,则其编码为gb2312。这种情况下,要进行编码转换,都需要先用decode方法将其转换成unicode编码,再使用encode方法将其转换成其他编码。通常,在没有指定特定的编码方式时,都是使用的系统默认编码创建的代码文件。&
如果字符串是这样定义:s=u'中文'
则该字符串的编码就被指定为unicode了,即python的内部编码,而与代码文件本身的编码无关。因此,对于这种情况做编码转换,只需要直接使用encode方法将其转换成指定编码即可。
如果一个字符串已经是unicode了,再进行解码则将出错,因此通常要对其编码方式是否为unicode进行判断:
isinstance(s, unicode)& #用来判断是否为unicode&
用非unicode编码形式的str来encode会报错&
&如何获得系统的默认编码?&
#!/usr/bin/env python
#coding=utf-8
import sys
print sys.getdefaultencoding()&&
该段程序在英文WindowsXP上输出为:ascii&
在某些IDE中,字符串的输出总是出现乱码,甚至错误,其实是由于IDE的结果输出控制台自身不能显示字符串的编码,而不是程序本身的问题。&
如在UliPad中运行如下代码:
会提示:UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)。这是因为UliPad在英文WindowsXP上的控制台信息输出窗口是按照ascii编码输出的(英文系统的默认编码是ascii),而上面代码中的字符串是Unicode编码的,所以输出时产生了错误。
将最后一句改为:print s.encode('gb2312')
则能正确输出“中文”两个字。
若最后一句改为:print s.encode('utf8')
则输出:\xe4\xb8\xad\xe6\x96\x87,这是控制台信息输出窗口按照ascii编码输出utf8编码的字符串的结果。
unicode(str,'gb2312')与str.decode('gb2312')是一样的,都是将gb2312编码的str转为unicode编码&
使用str.__class__可以查看str的编码形式
原理说了半天,最后来个包治百病的吧:)
#!/usr/bin/env python&
#coding=utf-8&
if isinstance(s, unicode):&
#s=u&中文&&
print s.encode('gb2312')&
#s=&中文&&
print s.decode('utf-8').encode('gb2312')

我要回帖

更多关于 scrapy 增量抓取 的文章

 

随机推荐