烦死人的编码问题

Python的网页编码问题(gb2312,gb系列)

没记错的话前面写过记录过一篇文章里面讲到了一些自己对Python编码解决的有关理解和方法,以为那样子应该就能解决所有的网页编码问题了。。。。原来是我太天真了[/捂脸]

事情起因:一天女朋友说想找几本电子书看,问我有没有推荐的。我当然没有,不过答应给她找,她说要到晋江文学网给她找找。于是就爽快的答应了。毕竟下小说这事也简单是吧。

结果呢:打开网站,准备按照套路下载小说,方发现死在了第一步。利用urlopen()打开一个网页准备读取的时候就显示乱码。查看网页charset编码:“gb2312”,按照以往的经验,采取重编码:decode(‘gbk2312’).encode(‘utf-8’).decode(‘utf-8’) 发现卵用没有,乱码一动不动让我好难受。在几经折腾下面,终于找到了解决办法。

解决乱码问题
!!!!--大多数网站都对支持gzip压缩的浏览器做了gzip的压缩,在python中可以通过gzip包处理gzip压缩过的网页--!!!!

意思是:网页对内容进行了压缩,我们如果直接对内容进行访问操作,并不能达到效果,所以我们需要先解压缩!

gzip是Python内置的一个库,所以我们可以直接import gzip,通过 gzip.decompress(response).decode(‘gbk’)来实现对内容解码。

释疑:这里解释下为什么后面解码成“gbk”而不是解码成“utf-8”的原因,首先因为gbk包含了gb2312的编码格式,其次是因为亲测utf-8编码还是会报错。。。

注意:并不是所有的网页都会采取gzip进行压缩传输。比如这个晋江小说网就比较调皮。它有的网站压缩,有的网站则没有。。所以实现我们应该采取判断。通过try,然后自己raise一个Error 来解决这个问题。具体关于小说内容的采集跟下载。稍后作简单分析。先给出源代码:

import urllib.request
from user_agent.base import generate_user_agent
import gzip
import re
import os, os.path
from bs4 import BeautifulSoup
from lxml.etree import HTML
import time
import random

def url_open(url):
    iplist = ['59.39.129.179:9000','163.125.22.169:9999','49.117.167.47:9999','116.52.65.217:9999','113.121.248.114:808','110.73.161.185:8123']
    # 有些代理不可用
    proxy = urllib.request.ProxyHandler({'https':random.choice(iplist)})
    opener = urllib.request.build_opener(proxy)
    urllib.request.install_opener(opener=opener)

    header = {'User-Agent': generate_user_agent()}
    req = urllib.request.Request(url=url, headers=header)
    # 如果IP失效,有三次重新尝试的机会
    try:
        response = urllib.request.urlopen(req).read()
    except:
        try:
            response = urllib.request.urlopen(req).read()
        except:
            response = urllib.request.urlopen(req).read()
    return response

# 传入参数:小说网站某一分类页面
# 函数返回:小说作者,书名,和小说的链接地址
def get_info(url):

    '''
    # 大多数网站都对支持gzip压缩的浏览器做了gzip的压缩,在python中可以通过gzip包处理gzip压缩过的网页”
    如果使用了代理,gzip 就会出错
    '''
    # 判断网页是否经过压缩处理
    try:
        response = url_open(url)
        response = gzip.decompress(response).decode('gbk','ignore')  # 解压缩内容并解码为“gbk”,'gb2312'&'utf-8'不行!
    except OSError as e:
        print(e)
        response = url_open(url).decode('gbk','ignore')
    soup = BeautifulSoup(response, "html.parser")

    authors = soup.find_all('a', href=re.compile("oneauthor\.php\?"), target='_blank')
    author = []
    for each in authors:
        author.append(each.string)

    titles = soup.find_all('a', href=re.compile("onebook\.php\?novel"), target="_blank")
    title = []
    for each in titles:
        title.append(each.string)

    links = soup.find_all('a', href=re.compile("onebook\.php\?novel"), target="_blank")
    link = []
    for each in links:
        link.append("http://www.jjwxc.net/" + each.get('href'))
    # print(author,'\n',title,'\n',link,'\n',len(author),'\n',len(title),'\n',len(link))
    return author, title, link

# 按顺序依次获得一页的所有章节链接
# 传入参数:某本小说的链接地址
# 函数返回:章节名字 跟 链接
def get_chapter(link):
    # 判断网页是否采用了gzip压缩格式
    try:
        response = url_open(link)
        response = gzip.decompress(response).decode('gbk','ignore')
    except OSError as e:
        print(e)
        response = url_open(link).decode('gbk','ignore')

    soup = BeautifulSoup(response,'html.parser')
    chapter_link = []
    chapter_title = []
    chapters = soup.find_all('a', itemprop="url", href=re.compile("chapterid="))
    for each in chapters:
        chapter_link.append(each.get('href'))
        chapter_title.append(each.string)
    #print(chapter_title,'\n',chapter_link, '\n', len(chapter_title), '\n', len(chapter_link))
    return chapter_title, chapter_link

# 函数描述:获取一个章节的内容
# 传入参数:某一个章节的链接地址
# 函数返回:一个章节的内容
def get_content(url):
    try:
        html = url_open(url)
        response = gzip.decompress(html).decode('gbk','ignore')  # 解压缩内容并解码为“gbk”,'gb2312'&'utf-8'不行!
    except OSError as e:
        print(e)
        response = url_open(url).decode('gbk','ignore')
    html = HTML(response)
    content = html.xpath('//div[@class="noveltext"]/text()')
    #print(content)
    return content

# 函数描述:保存一个章节的内容
# 传入参数:小说名,章节名,章节内容
def save_novel(novelname, author, chapter_title, chapter_content, folder="晋江小说"):
    if not os.path.exists(folder):
        os.mkdir(folder)
    else:
        pass
    novelname = novelname
    content = chapter_content
    with open(folder+'/'+novelname+'.txt','a+') as f:
        try:
            #f.write("\t\t\t"+novelname+ '-----' + author + '\r\n')
            f.write(chapter_title)
            for eachline in content:
                eachline = eachline.replace('\u3000','')
                eachline = eachline.replace('\u2022','')
                f.writelines(eachline+'\n')
        except:
            pass

# 函数描述:保存单本小说
# 传入参数:小说名,小说地址
def main(novelname, author, novel_url, ):
    chapter_title, chapter_link = get_chapter(novel_url)  # 获取所有章节的名字跟地址
    chapter_zip = list(zip(chapter_title, chapter_link))    #

    for each in chapter_zip:
        chapter_content = get_content(each[1])     # 获取一个章节的内容
        print("正在下载:%s --> %s" % (novelname, each[0]))
        save_novel(novelname=novelname, author=author, chapter_title=each[0], chapter_content=chapter_content)

if __name__=="__main__":
    # 翻页   如果用多个线程的话应该会快蛮多。
    for page in range(1,1000):
        print("第%d页----->"%page)
        url = "http://www.jjwxc.net/bookbase_slave.php?booktype=free&opt=&page={page}&orderstr=4&endstr=true".format(page=page)
        # 获得分类页的小说信息:作者,小说名,小说地址
        novel_authors, novel_names, novel_links = get_info(url)
        # 将小说对应信息整理
        novel_zip = list(zip(novel_names, novel_authors, novel_links))
        for novel in novel_zip:
            print("这是第 %d 本小说" %(novel_zip.index(novel)+1))
            print("\n---------------- %s -----------------\n" % novel[0])
            main(novelname=novel[0],author=novel[1],novel_url=novel[2])
            print("---------------- %s -----------------\n" % novel[0])
            #time.sleep(1)       # 每隔三秒下载一本电子书

源码的简单分析:

主要用到的模块与方法:urllib,BeautifulSoup,gzip,xpath

写了一个通用的打开网页函数,里面从网上随便找了几个代理,防止被封。因为我打算下载很多电子书的本来。每一页有30本左右,准备翻个 1K 页的,如果下载一两页并不需要这个。
之所以写了三个 try,是来判断IP是否可用。不可用就换一个。毕竟临时用。将就下了就

几个主要函数都做了注释,原理很简单。
主要思路就是写一个保存一本小说的函数,然后不断迭代保存。

亲测速度很慢。所以建议开线程来下载小说。可以是分每一页做一个线程这样可以提高不少下载速度。这里我就没有去写了。毕竟没真打算把1K*30 本小说全扒下来。有想法的可以去试试!

好了,就这么多吧。希望能够帮到遇到类似问题的朋友

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值