Skip to content

Commit 262c4cb

Browse files
committed
Merge branch 'pdf_refactor'
2 parents a586700 + 18c0683 commit 262c4cb

11 files changed

Lines changed: 352 additions & 92 deletions

File tree

heart/test.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# -*- coding:utf-8 -*-
2+
import jieba
3+
4+
print " ".join(jieba.cut(u":: [AVI/329M][C0930-hitozuma1007] 坂井雪恵 Yukie Sakai (308123)"))

pdf/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ python crawler.py
3939

4040
3. 生成的PDF文件可以在公众号回复『pdf』下载
4141

42+
### 更新记录
43+
44+
* 2017-2-21: 对代码进行了全面的重构,可扩展, 子类爬虫只需实现 `parse_menu``parse_body`方法就可以实现HTML转换PDF的逻辑
45+
4246

4347
### Contact me
4448

pdf/crawler.py

Lines changed: 132 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
# coding=utf-8
2+
import logging
23
import os
34
import re
45
import time
5-
import logging
6+
7+
try:
8+
from urllib.parse import urlparse # py3
9+
except:
10+
from urlparse import urlparse # py2
11+
612
import pdfkit
713
import requests
814
from bs4 import BeautifulSoup
@@ -21,103 +27,137 @@
2127
"""
2228

2329

24-
def parse_url_to_html(url, name):
30+
class Crawler(object):
2531
"""
26-
解析URL,返回HTML内容
27-
:param url:解析的url
28-
:param name: 保存的html文件名
29-
:return: html
32+
爬虫基类,所有爬虫都应该继承此类
3033
"""
31-
try:
34+
name = None
35+
36+
def __init__(self, name, start_url):
37+
"""
38+
初始化
39+
:param name: 保存问的PDF文件名,不需要后缀名
40+
:param start_url: 爬虫入口URL
41+
"""
42+
self.name = name
43+
self.start_url = start_url
44+
self.domain = '{uri.scheme}://{uri.netloc}'.format(uri=urlparse(self.start_url))
45+
46+
def crawl(self, url):
47+
"""
48+
pass
49+
:return:
50+
"""
51+
print(url)
3252
response = requests.get(url)
33-
soup = BeautifulSoup(response.content, 'html.parser')
34-
# 正文
35-
body = soup.find_all(class_="x-wiki-content")[0]
36-
# 标题
37-
title = soup.find('h4').get_text()
38-
39-
# 标题加入到正文的最前面,居中显示
40-
center_tag = soup.new_tag("center")
41-
title_tag = soup.new_tag('h1')
42-
title_tag.string = title
43-
center_tag.insert(1, title_tag)
44-
body.insert(1, center_tag)
45-
html = str(body)
46-
# body中的img标签的src相对路径的改成绝对路径
47-
pattern = "(<img .*?src=\")(.*?)(\")"
48-
49-
def func(m):
50-
if not m.group(3).startswith("http"):
51-
rtn = m.group(1) + "http://www.liaoxuefeng.com" + m.group(2) + m.group(3)
52-
return rtn
53-
else:
54-
return m.group(1)+m.group(2)+m.group(3)
55-
html = re.compile(pattern).sub(func, html)
56-
html = html_template.format(content=html)
57-
html = html.encode("utf-8")
58-
with open(name, 'wb') as f:
59-
f.write(html)
60-
return name
61-
62-
except Exception as e:
63-
64-
logging.error("解析错误", exc_info=True)
65-
66-
67-
def get_url_list():
53+
return response
54+
55+
def parse_menu(self, response):
56+
"""
57+
解析目录结构,获取所有URL目录列表:由子类实现
58+
:param response 爬虫返回的response对象
59+
:return: url 可迭代对象(iterable) 列表,生成器,元组都可以
60+
"""
61+
raise NotImplementedError
62+
63+
def parse_body(self, response):
64+
"""
65+
解析正文,由子类实现
66+
:param response: 爬虫返回的response对象
67+
:return: 返回经过处理的html文本
68+
"""
69+
raise NotImplementedError
70+
71+
def run(self):
72+
start = time.time()
73+
options = {
74+
'page-size': 'Letter',
75+
'margin-top': '0.75in',
76+
'margin-right': '0.75in',
77+
'margin-bottom': '0.75in',
78+
'margin-left': '0.75in',
79+
'encoding': "UTF-8",
80+
'custom-header': [
81+
('Accept-Encoding', 'gzip')
82+
],
83+
'cookie': [
84+
('cookie-name1', 'cookie-value1'),
85+
('cookie-name2', 'cookie-value2'),
86+
],
87+
'outline-depth': 10,
88+
}
89+
htmls = []
90+
for index, url in enumerate(self.parse_menu(self.crawl(self.start_url))):
91+
html = self.parse_body(self.crawl(url))
92+
f_name = ".".join([str(index), "html"])
93+
with open(f_name, 'wb') as f:
94+
f.write(html)
95+
htmls.append(f_name)
96+
97+
pdfkit.from_file(htmls, self.name + ".pdf", options=options)
98+
for html in htmls:
99+
os.remove(html)
100+
total_time = time.time() - start
101+
print(u"总共耗时:%f 秒" % total_time)
102+
103+
104+
class LiaoxuefengPythonCrawler(Crawler):
68105
"""
69-
获取所有URL目录列表
70-
:return:
106+
廖雪峰Python3教程
71107
"""
72-
response = requests.get("http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000")
73-
soup = BeautifulSoup(response.content, "html.parser")
74-
menu_tag = soup.find_all(class_="uk-nav uk-nav-side")[1]
75-
urls = []
76-
for li in menu_tag.find_all("li"):
77-
url = "http://www.liaoxuefeng.com" + li.a.get('href')
78-
urls.append(url)
79-
return urls
80108

81-
82-
def save_pdf(htmls, file_name):
83-
"""
84-
把所有html文件保存到pdf文件
85-
:param htmls: html文件列表
86-
:param file_name: pdf文件名
87-
:return:
88-
"""
89-
options = {
90-
'page-size': 'Letter',
91-
'margin-top': '0.75in',
92-
'margin-right': '0.75in',
93-
'margin-bottom': '0.75in',
94-
'margin-left': '0.75in',
95-
'encoding': "UTF-8",
96-
'custom-header': [
97-
('Accept-Encoding', 'gzip')
98-
],
99-
'cookie': [
100-
('cookie-name1', 'cookie-value1'),
101-
('cookie-name2', 'cookie-value2'),
102-
],
103-
'outline-depth': 10,
104-
}
105-
pdfkit.from_file(htmls, file_name, options=options)
106-
107-
108-
def main():
109-
start = time.time()
110-
urls = get_url_list()
111-
file_name = u"liaoxuefeng_Python3_tutorial.pdf"
112-
htmls = [parse_url_to_html(url, str(index) + ".html") for index, url in enumerate(urls)]
113-
save_pdf(htmls, file_name)
114-
115-
for html in htmls:
116-
os.remove(html)
117-
118-
total_time = time.time() - start
119-
print(u"总共耗时:%f 秒" % total_time)
109+
def parse_menu(self, response):
110+
"""
111+
解析目录结构,获取所有URL目录列表
112+
:param response 爬虫返回的response对象
113+
:return: url生成器
114+
"""
115+
soup = BeautifulSoup(response.content, "html.parser")
116+
menu_tag = soup.find_all(class_="uk-nav uk-nav-side")[1]
117+
for li in menu_tag.find_all("li"):
118+
url = li.a.get("href")
119+
if not url.startswith("http"):
120+
url = "".join([self.domain, url]) # 补全为全路径
121+
yield url
122+
123+
def parse_body(self, response):
124+
"""
125+
解析正文
126+
:param response: 爬虫返回的response对象
127+
:return: 返回处理后的html文本
128+
"""
129+
try:
130+
soup = BeautifulSoup(response.content, 'html.parser')
131+
body = soup.find_all(class_="x-wiki-content")[0]
132+
133+
# 加入标题, 居中显示
134+
title = soup.find('h4').get_text()
135+
center_tag = soup.new_tag("center")
136+
title_tag = soup.new_tag('h1')
137+
title_tag.string = title
138+
center_tag.insert(1, title_tag)
139+
body.insert(1, center_tag)
140+
141+
html = str(body)
142+
# body中的img标签的src相对路径的改成绝对路径
143+
pattern = "(<img .*?src=\")(.*?)(\")"
144+
145+
def func(m):
146+
if not m.group(3).startswith("http"):
147+
rtn = "".join([m.group(1), self.domain, m.group(2), m.group(3)])
148+
return rtn
149+
else:
150+
return "".join([m.group(1), m.group(2), m.group(3)])
151+
152+
html = re.compile(pattern).sub(func, html)
153+
html = html_template.format(content=html)
154+
html = html.encode("utf-8")
155+
return html
156+
except Exception as e:
157+
logging.error("解析错误", exc_info=True)
120158

121159

122160
if __name__ == '__main__':
123-
main()
161+
start_url = "http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000"
162+
crawler = LiaoxuefengPythonCrawler("廖雪峰Git", start_url)
163+
crawler.run()

pdf/requirement.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
requests==2.12.4
2+
beautifulsoup4==4.5.3
3+
pdfkit==0.6.1

runoob2pdf/README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#Python 爬虫:把runoob网站上的各类教程转换成 PDF 电子书
2+
3+
### 系统要求
4+
python3.4以上版本, 不支持python2.x
5+
6+
7+
### 准备工具
8+
9+
requests、beautifulsoup 是爬虫两大神器,reuqests 用于网络请求,beautifusoup 用于操作 html 数据。有了这两把梭子,干起活来利索。scrapy 这样的爬虫框架我们就不用了,这样的小程序派上它有点杀鸡用牛刀的意思。此外,既然是把 html 文件转为 pdf,那么也要有相应的库支持, wkhtmltopdf 就是一个非常的工具,它可以用适用于多平台的 html 到 pdf 的转换,pdfkit 是 wkhtmltopdf 的Python封装包。click是一款命令行工具参数工具,用于在命令行传递参数。
10+
11+
首先安装好下面的依赖包
12+
13+
```python
14+
pip install requests
15+
pip install beautifulsoup4
16+
pip install pdfkit
17+
pip install click
18+
```
19+
20+
### 安装 wkhtmltopdf
21+
Windows平台直接在 [http://wkhtmltopdf.org/downloads.html](http://wkhtmltopdf.org/downloads.html) 下载稳定版的 wkhtmltopdf 进行安装,安装完成之后把该程序的执行路径加入到系统环境 $PATH 变量中,否则 pdfkit 找不到 wkhtmltopdf 就出现错误 “No wkhtmltopdf executable found”。Ubuntu 和 CentOS 可以直接用命令行进行安装
22+
23+
```shell
24+
$ sudo apt-get install wkhtmltopdf # ubuntu
25+
$ sudo yum intsall wkhtmltopdf # centos
26+
```
27+
28+
### 运行
29+
```python
30+
python runoob2pdf.py
31+
```
32+
33+
### 说明
34+
执行 python runoob2pdf.py后
35+
会提示让你输入
36+
1. runoob网站上的教程主页地址,主页地址就是网页顶部菜单上对应的地址。
37+
如效果图。
38+
2. 输入保存的pdf文件名。
39+
40+
### 效果图
41+
![image](./runoob2pdf.jpg)
42+
![image](./runoob2pdf_1.jpg)
43+
![image](./runoob2pdf_2.jpg)
44+
![image](./runoob2pdf_3.jpg)
45+
46+
### 特别说明
47+
感谢《Python 爬虫:把廖雪峰的教程转换成 PDF 电子书》的作者liuzhijun,本项目的代码都是基于他的代码改动后实现。
48+
49+
### Contact me
50+
>作者:jadentseng
51+
>微信: cheney2010
52+
53+

runoob2pdf/__init__.py

Whitespace-only changes.

runoob2pdf/runoob2pdf.jpg

37.9 KB
Loading

0 commit comments

Comments
 (0)