1.概述
由于平时喜欢看书,但是发现一些推送的服务号没有自己想要的电子书,最近再学习爬虫,就想小试牛刀,主要用到的技术:
使用python
的requests
模块进行网站信息的爬取
解析我使用了两个方式,正则表达式和pyquery
库进行html
的解析
由于kindle
推送,主要使用的是邮箱发送的方式,所以使用python
已经封装好的email
模块和smtplib
模块,发送附件至你的kindle
邮箱
主要的功能模块实现:
检索书籍然后推送至kindle
排行榜推送至kindle
2.各模块实现
2.1 排行榜采集模块
采集网页信息
主要使用的是requests
模块。
def spider_qishu(url,headers):
response=requests.get(url,headers=headers)
if response.status_code==200:
return response.text
return None
函数功能:get
请求将网页的内容读取
解析html
中的关键信息,并将其返回
def tuijian(html):
result=re.findall('<font>(.*?)</font>.*?<u style=.*?<em>(.*?)</em><a href="(.*?)">(.*?)</a></u>',html,re.S)
paihangbang=re.findall('<h2>(.*?)</h2>',html,re.S)
print(paihangbang[0])
results=[]
for item in result:
t={}
t['index']=item[0]
t['author']=item[1]
t['href']=item[2]
t['book_name']=item[3]
results.append(t)
for i in results:
print('序号:'+i['index']+' 作者:'+i['author']+' 书名:'+i['book_name']+' 链接:'+i['href'])
return results
这里将解析的结果存放再results
,results
是一个列表,然后它的每个元素是一个字典,分别存储序号,作者,书名,以及书的链接,这个链接的网页存在着下载地址,下面我们还要将其爬取,解析其下载地址。
下载模块:
def download(number,results,base_url,headers):
number=int(number)-1
extend_url=results[number]['href']
url=base_url+extend_url
headers['Referer']=url
response=requests.get(url)
content=response.content.decode('utf-8')
out=re.findall('get_down_url.*?,\'(.*?)\',',content,re.S)
download_url=out[0]
print(download_url)
print('正在下载请耐心等候。。。。。。。\n')
filename=results[number]['book_name']+'.txt'
try:
r=requests.get(download_url,headers=headers)
if r.status_code==200:
with open(filename,'wb') as f:
f.write(r.content)
else:
print(r.status_code)
except RequestException as e:
print(e)
return filename
首先我们从链接地址中得到网页,然后用正则表达式解析网页获得下载地址,然后将其写入文件,最后使用我们封装的send_email
函数将其发送至kindle
总结:解析网页这边使用的是正则表达式,发现正则表达式很不方便,很容易写错,十分麻烦。所以推荐再解析库的使用上使用lxml
模块,或者使用pyquery
模块,两个的解析速度都很快,beautiful soup
很慢,而且它的css
选择器没有pyquery
模块的强大,如果你对jquery
熟悉的话,推荐使用pyquery
模块。
2.2 检索下载电子书
思路还是和上面的一样,不过再解析html
网页我使用的是pyquery
模块,它主要是根据css
选择节点,进行网页的解析,速度很快,而且很方便。
分页模块
当你搜索一本书的时候,可能相似的书有很多,网页会将其分页,我们使用fiddler
分析网页的请求过程,首先网页会将20
个书分为一页,然后再get
请求的时候会添加一个page
字段,所以我们首先得得到一共检索有numbe
r本书,然后用math
模块的ceil
方法,对number/20
取上,最后得到网页的页数,我们再迭代对每一页发出请求解析到每本书所在的链接。在做这个模块的时候,我不幸踩到了坑,网页的请求url
地址中的word
字段编码是gb2312
,所以这边需要进行编码。
def page_parse():
href={}
name_href={}
base_url='http://www.qishu.cc/search.asp'
keyword=input("请输入你要搜索的书籍:\n")
data={}
data['word']=keyword.encode('gb2312')
response=requests.get(base_url,data=data)
doc=pq(response.text)
spans=doc('#searchmain .searchResult span:first-child')
print("一共拥有"+spans.text()+"本书:\n")
numbers=int(spans.text())
pages=math.ceil(numbers/20)
for i in range(pages):
i=i+1
data['page']=str(i)
new_response=requests.get(base_url,data=data)
links,names=search(new_response,href,name_href)
return links,names
检索所有书籍模块
使用循环迭代,将书籍打印出来,并存储所在的页面信息,书所在的链接,名字
def search(response,href,name_href):
response.encoding='gb2312'
doc=pq(response.text)
results=doc('#searchmain .searchTopic').items()
for result in results:
a=result.find('a').remove('font')
result.find('a').remove()
print('序号 '+result.text().rstrip('、'))
print('书名 '+a.text())
print('链接 '+a.attr('href'))
href[result.text().rstrip('、')]=a.attr('href')
name_href[result.text().rstrip('、')]=a.text()
return href,name_href
下载模块
使用上面得到的链接,然后找到书所在的页面,解析下载地址,然后写入文件,返回文件名
def download_search(links,number,filename):
base_url='http://www.qishu.cc'
for key,value in links.items():
if key==number:
url=base_url+value
response=requests.get(url)
response.encoding='gb2312'
content=pq(response.text)
temp=content('#downAddress a:gt(0)').remove('b')
download_url=temp.attr('href')
try:
r=requests.get(download_url)
if r.status_code==200:
with open(filename,'wb') as f:
f.write(r.content)
else:
print(r.status_code)
except RequestException as e:
print(e)
print('下载完成')
return filename
2.3 邮箱推送模块
下面只要将qq
邮箱和16
位授权码、kindle
邮箱地址替换成你的就可以使用了,send_mail
我将除了filename
之外的所有形参设置成默认参数,这样不用调用的使用给他传值。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import smtplib
import email.mime.multipart
import email.mime.text
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
def send_email(filename,smtpHost='smtp.qq.com', sendAddr='qq邮箱', password='16位授权码', recipientAddrs='kindle邮箱地址', subject='kindle推送', content='推送小说'):
msg = email.mime.multipart.MIMEMultipart()
msg['from'] = sendAddr
msg['to'] = recipientAddrs
msg['subject'] = subject
content = content
txt = email.mime.text.MIMEText(content, 'plain', 'utf-8')
msg.attach(txt)
part = MIMEApplication(open(filename,'rb').read())
part.add_header('Content-Disposition', 'attachment', filename=filename)
msg.attach(part)
smtp = smtplib.SMTP()
smtp.connect(smtpHost, '25')
smtp.login(sendAddr, password)
smtp.sendmail(sendAddr, recipientAddrs, str(msg))
print("发送成功!")
smtp.quit()
总结:还可以在爬取分页数据的时候,采用多线程,这样就会速度很快,然后下载的时候可以做个进度条。