使用Python爬取mobi格式电纸书
最近做了个微信推送kindle电子书的公众号:kindle免费书库
不过目前电子书不算非常多,所以需要使用爬虫来获取足够书籍。
于是,写了以下这个爬虫,来爬取kindle114的电子书。
值得注意的地方:
当爬取数过大时,由于对方有开启放抓取,会返回一个javascript而非原始的html,所以我使用
的PyV8来执行这段js从而拿到真正的地址。
目前存在的问题:
正则式写得还不够好,毕竟是第一次正式写爬虫:)
无法下载需要购买的附件
爬虫为单线程,爬完整个网站速度慢。我有试过转成多进程,但是貌似由于不能同时登陆,大多数
爬虫进程都无法正常爬取@@
# -*- coding: utf-8 -*-
import urllib2
import re
import requests
import os
import hashlib def fuckJS(js):
import PyV8
import re
#去掉<script>标签
js=js[31:-9]
for st in ['window','location',"'assign'","'href'","'replace'"]:
equal=re.findall('[_A-Za-z0-9 =]+%s;'%st,js)#找到变量赋值等式
if equal==[]:#有可能没有
continue
else:
equal=equal[0]
var=equal.split('=')[0].strip()#找出变量名
#把等式干掉
js=js.replace(equal,'')
#把变量替换成它真正的意思
js=js.replace(var,st)
#把['xx'] 替换成 .xx
js=js.replace("['%s']"%st.strip("'"),'.%s'%st.strip("'"))
#将 window.href= 后的内容踢掉,因为当PyV8只输出最后一个等式的值
if re.findall('window\.href=.+',js)!=[]:
js=js.replace(re.findall('window\.href=.+',js)[0],'')
#删掉location.xxx=
js=js.replace('location.href=','').replace('location.replace','').replace('location.assign','')
#交给你了-v-
ctxt2 = PyV8.JSContext()
ctxt2.enter()
#print ctxt2.eval(js)
trueAddr = ctxt2.eval(js)
print trueAddr
return trueAddr def downloadMobi(name, url):
#去掉windows下不合法的文件名
unlawName = '<>/\\|:""*?'
for i in unlawName:
name = name.replace(i, '')
#正则表达式写的不够好导致的问题@@
if name.count(' img src=templateyeei_dream1cssyeeidigest_1.gif class=vm alt= title= ') > 0:
name = name.split('  ')[0]+'.mobi'
#避免重复下载
if os.path.exists('D:\Kindle114SpiderDownload\\' + name):
print 'already have', name
return
url = url.split(' ')[0]
s = requests.session()
username = '你的用户名'
password = '你的密码'
passwordMd5 = hashlib.md5(password).hexdigest()
data = {'formhash': '23cd6c29', 'referer': '','username': username, 'password': passwordMd5, 'questionid':'', 'answer':''}
res=s.post('http://www.kindle114.com/member.php?mod=logging&action=login&loginsubmit=yes&loginhash=LYn7n&inajax=1',data) #res = s.get('http://www.kindle114.com/forum.php?mod=attachment&aid=MTQ2NTB8ZjhkNjY3NmF8MTQxNjg5OTYxOXw0NDIxfDczNjI%3D')
try:
res = s.get(url, timeout = 200)
except:
print 'time out for ', name
#print 'content[:50]'
#print res.content[:50]
if res.content.count('<!DOCTYPE html') > 0:
print '!!!!!!!!!!!!!!!!!not a mobi, this file need gold coin!!!!!!!!!!!!!!!'
return
try:
with open('D:\\Kindle114SpiderDownload\\' + name, "wb") as code:
code.write(res.content)
except:
print '!!!!!!!!!!!!!!!!!!!!!遇到不合法文件名!!!!!!!!!!!!!!!!!!', name def spiderThread(url, threadName):
req = urllib2.urlopen(url, timeout = 10)
text = req.read()
if text.count('<!DOCTYPE html') == 0:
js = text
trueURL = 'http://www.kindle114.com/' + fuckJS(js)
print 'trueURL', trueURL
req = urllib2.urlopen(trueURL)
text = req.read() #href = '<a href="(.*?)" onmouseover="showMenu({\'ctrlid\':this.id,\'pos\':\'12\'})" id=.*?target="_blank">(.*?)</a>'
href = '<a href="(.*?)".*?target="_blank">(.*?)</a>'
href_re = re.compile(href)
href_info = href_re.findall(text) bookSum = 0
for i in href_info:
if i[1].count('.mobi') > 0:
bookSum+=1
if bookSum == 0:
print '!!!bookSum = 0!!!!', text[:100]
if bookSum == 1:
print 'only one book in this thread'
bookFileName = threadName + '.mobi'
for i in href_info:
if i[1].count('.mobi') > 0:
link = i[0].replace('amp;','')
break
print link, bookFileName
downloadMobi(bookFileName, link)
else:
print str(bookSum), 'in this thread'
for i in href_info:
if i[1].count('.mobi') > 0:
link = i[0].replace('amp;','')
bookFileName = i[1]
print link, bookFileName
downloadMobi(bookFileName, link) for pageNum in range(1, 125):
url = 'http://www.kindle114.com/forum.php?mod=forumdisplay&fid=2&filter=sortid&sortid=1&searchsort=1&geshi=1&page=' + str(pageNum)
print '=============url', url,'==============='
try:
req = urllib2.urlopen(url, timeout = 10)
except:
print 'page time out', url
text = req.read()
href = '<h4><a href="(.*?)" target="_blank" class="xst">(.*?)<span class="xi1">'
href_re = re.compile(href)
href_info = href_re.findall(text)
for i in href_info:
print i[0], i[1]
url = 'http://www.kindle114.com/'+i[0]
threadName = i[1]
try:
spiderThread(url, threadName)
except Exception , e:
print '!!!!!!!!!!!!! Error with ',threadName, url,'!!!!!!!!!!!!!!!!'
print e
raw_input('finish all!!!')
使用Python爬取mobi格式电纸书的更多相关文章
- python爬取网站数据
开学前接了一个任务,内容是从网上爬取特定属性的数据.正好之前学了python,练练手. 编码问题 因为涉及到中文,所以必然地涉及到了编码的问题,这一次借这个机会算是彻底搞清楚了. 问题要从文字的编码讲 ...
- Python:爬取乌云厂商列表,使用BeautifulSoup解析
在SSS论坛看到有人写的Python爬取乌云厂商,想练一下手,就照着重新写了一遍 原帖:http://bbs.sssie.com/thread-965-1-1.html #coding:utf- im ...
- 利用Python爬取豆瓣电影
目标:使用Python爬取豆瓣电影并保存MongoDB数据库中 我们先来看一下通过浏览器的方式来筛选某些特定的电影: 我们把URL来复制出来分析分析: https://movie.douban.com ...
- python爬取人民币汇率中间价
python爬取人民币汇率中间价,从最权威的网站中国外汇交易中心. 首先找到相关网页,解析链接,这中间需要经验和耐心,在此不多说. 以人民币兑美元的汇率为例(CNY/USD),脚本详情如下: wind ...
- python爬取网站数据保存使用的方法
这篇文章主要介绍了使用Python从网上爬取特定属性数据保存的方法,其中解决了编码问题和如何使用正则匹配数据的方法,详情看下文 编码问题因为涉及到中文,所以必然地涉及到了编码的问题,这一次借这 ...
- Python爬取豆瓣电影top
Python爬取豆瓣电影top250 下面以四种方法去解析数据,前面三种以插件库来解析,第四种以正则表达式去解析. xpath pyquery beaufifulsoup re 爬取信息:名称 评分 ...
- Python 爬取淘宝商品数据挖掘分析实战
Python 爬取淘宝商品数据挖掘分析实战 项目内容 本案例选择>> 商品类目:沙发: 数量:共100页 4400个商品: 筛选条件:天猫.销量从高到低.价格500元以上. 爬取淘宝商品 ...
- steam夏日促销悄然开始,用Python爬取排行榜上的游戏打折信息
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 不知不觉,一年一度如火如荼的steam夏日促销悄然开始了.每年通过大大小小 ...
- 用Python爬取B站、腾讯视频、爱奇艺和芒果TV视频弹幕!
众所周知,弹幕,即在网络上观看视频时弹出的评论性字幕.不知道大家看视频的时候会不会点开弹幕,于我而言,弹幕是视频内容的良好补充,是一个组织良好的评论序列.通过分析弹幕,我们可以快速洞察广大观众对于视频 ...
随机推荐
- 【Git】五、远程仓库
前面4节将的都是本地的git操作,这节开始讲合并到本地分支后,如何与远程仓库做交互 -------------------------------- 提要 //生成本地ssh密钥 $ ssh-keyg ...
- yum list报一些error的组件
1 删除那些无效的参数配置,就不再报错了
- 随意软连接/home/users目录导致环境变量消失后的事故
1 自己的用户zj下,把/home/zj 删除后用ln -s软连接其他目录,导致了当前用户的.bash_profile失效 2 解决思路 第一,删除软连接 rm -rf /home/zj 记住后面 ...
- Centos7虚拟机根分区扩展
线上的kvm虚拟机,原来只规划了8G,后来发现硬盘动不动就被日志塞满了,需要进行扩容. 扩容步骤如下: 1.先把kvm虚拟机关机 2.在宿主机上进行kvm虚拟机的磁盘扩容 qemu-img resiz ...
- (6)python基础数据类型
python的六大标准数据类型 (一)Number 数字类型(int float bool complex) (二)String 字符串类型 (三)List 列表类型 (四)Tuple 元组类型 ...
- linux——常用命令
学习linux命令地址: 学习命令地址,可参考http://linux.51yip.com/ 在文件中搜索指定字符串 grep -i "requirepass" redis.con ...
- P5357 【模板】AC自动机(二次加强版)
思路 这题可以同时作为AC自动机和SAM的模板啊喂 AC自动机 对T建出AC自动机,把S在上面匹配,然后记录每个点被经过的次数,最后统计一次即可(暴力跳fail的复杂度是不对的) SAM 对S建出SA ...
- barcode模块: plus.barcode.scan 进行扫描图片出现无法识别二维码,打印的错误信息是code:8,message:''
原因之一:图片的像素太大了,无法识别. 解决方法: 压缩一下图片. 这里的 data 我放了一个 像素为 4040 × 4040 的 图片. 进行识别的时候会报, (无法识别的图片,都是返回这些值) ...
- spring boot 入门 使用spring.profiles.active来分区配置(转)
很多时候,我们项目在开发环境和生成环境的环境配置是不一样的,例如,数据库配置,在开发的时候,我们一般用测试数据库,而在生产环境的时候,我们是用正式的数据,这时候,我们可以利用profile在不同的环境 ...
- [Python自学] day-18 (1) (JS正则、第三方组件)
一.JS的正则表达式 JS正则提供了两个方法: test():用于判断字符串是否符合规定: exec():获取匹配的数据: 1.test() 定义一个正则表达式: reg = /\d+/; // 用于 ...