最近閑來無事,拿來練練手。
注:
由于網站可能會變動,本代碼不保證後面一直都能用,僅講述抓取的思路;
個人純屬研究使用,請不要應用于商業目的;
使用語言:Python
版本:3.4.3
代碼也比較簡單,直接貼上來:
HttpClient.py
1
2
3
4
5
6
7
8
9
10
11
12
<code># -*- coding: utf-8 -*-</code>
<code>import</code> <code>requests</code>
<code>def</code> <code>make_request(url):</code>
<code> </code><code>print</code><code>(</code><code>'make_request: '</code><code>, url)</code>
<code> </code><code>r </code><code>=</code> <code>requests.get(url, timeout</code><code>=</code><code>(</code><code>30</code><code>, </code><code>90</code><code>))</code>
<code># if r.status_code == 200:</code>
<code> </code><code>print</code><code>(</code><code>'content-type: '</code><code>, r.headers[</code><code>'content-type'</code><code>])</code>
<code> </code><code>print</code><code>(</code><code>'encoding: '</code><code>, r.encoding)</code>
<code> </code><code>print</code><code>(</code><code>'apparent_encoding: '</code><code>, r.apparent_encoding)</code>
<code> </code><code>return</code> <code>r</code>
Kanunu8.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<code>import</code> <code>os</code>
<code>import</code> <code>sys</code>
<code>import</code> <code>re</code>
<code>import</code> <code>encodings</code>
<code>#為了引用與父目錄同級檔案夾中的方法</code>
<code>sys.path.append(</code><code>".."</code><code>)</code>
<code># 解決gb2312亂碼問題</code>
<code>encodings.aliases.aliases[</code><code>'gb2312'</code><code>] </code><code>=</code> <code>'gb18030'</code>
<code>from</code> <code>bs4 </code><code>import</code> <code>BeautifulSoup</code>
<code>from</code> <code>_pyio </code><code>import</code> <code>open</code>
<code>from</code> <code>util </code><code>import</code> <code>*</code>
<code>book_url </code><code>=</code> <code>''</code>
<code>book_name </code><code>=</code> <code>''</code>
<code>#屏蔽掉作者的連結</code>
<code>writer_link_pattern </code><code>=</code> <code>re.</code><code>compile</code><code>(r</code><code>'.*/writer/\d+\.html'</code><code>)</code>
<code>#由于我用的是Windows平台,檔案名中不能包含下列非法字元,需要過濾</code>
<code>window_illegal_file_name_pattern </code><code>=</code> <code>re.</code><code>compile</code><code>(r</code><code>'[\\|/|:|\*|\?|"|<|>|\|]'</code><code>)</code>
<code> </code>
<code>def</code> <code>find_tbody(tag):</code>
<code> </code><code>if</code> <code>tag.name </code><code>=</code><code>=</code> <code>'tbody'</code><code>:</code>
<code> </code><code>if</code> <code>tag.find(</code><code>'tbody'</code><code>) </code><code>is</code> <code>None</code> <code>and</code> <code>tag.find(</code><code>'strong'</code><code>).string </code><code>=</code><code>=</code> <code>'正文'</code><code>:</code>
<code> </code><code>return</code> <code>True</code>
<code> </code><code>elif</code> <code>'釋出時間'</code> <code>in</code> <code>tag.get_text():</code>
<code> </code><code>return</code> <code>False</code>
<code>def</code> <code>strong_with_no_href(tag):</code>
<code> </code><code>return</code> <code>tag.name </code><code>=</code><code>=</code> <code>'strong'</code> <code>and</code> <code>tag.a </code><code>is</code> <code>None</code> <code>and</code> <code>tag.font </code><code>is</code> <code>not</code> <code>None</code>
<code>def</code> <code>find_title(tag):</code>
<code> </code><code>if</code> <code>tag.h1 </code><code>is</code> <code>not</code> <code>None</code><code>:</code>
<code> </code><code>return</code> <code>tag.h1.font.string</code>
<code> </code><code>elif</code> <code>tag.h2 </code><code>is</code> <code>not</code> <code>None</code><code>:</code>
<code> </code><code>return</code> <code>tag.h2.font.string</code>
<code> </code><code>else</code><code>:</code>
<code> </code><code>return</code> <code>tag.find(strong_with_no_href).font.string</code>
<code>def</code> <code>make_soup(html):</code>
<code> </code><code># , from_encoding='gb18030'</code>
<code> </code><code>soup </code><code>=</code> <code>BeautifulSoup(html, </code><code>"html.parser"</code><code>)</code>
<code> </code><code>print</code><code>(</code><code>'original_encoding: '</code><code>, soup.original_encoding, </code><code>', declared_html_encoding: '</code><code>, soup.declared_html_encoding, </code><code>', from_encoding: '</code><code>, soup.from_encoding)</code>
<code> </code><code>return</code> <code>soup</code>
<code>def</code> <code>get_legal_window_file_name(name):</code>
<code> </code><code>if</code> <code>name </code><code>is</code> <code>None</code><code>:</code>
<code> </code><code>return</code> <code>'unknown'</code>
<code> </code><code>return</code> <code>window_illegal_file_name_pattern.sub('', name)</code>
<code>if</code> <code>__name__ </code><code>=</code><code>=</code> <code>'__main__'</code><code>: </code>
<code> </code><code>book_url </code><code>=</code> <code>input</code><code>(</code><code>'請輸入電子書URL:'</code><code>)</code>
<code> </code><code># 按任意鍵繼續</code>
<code># if input('請按任意鍵開始抓取...'):</code>
<code># pass</code>
<code> </code><code>#擷取Html内容</code>
<code> </code><code>request </code><code>=</code> <code>HttpClient.make_request(book_url)</code>
<code> </code><code>html </code><code>=</code> <code>request.content</code>
<code> </code><code>soup </code><code>=</code> <code>make_soup(html)</code>
<code> </code><code># 爬取書名</code>
<code> </code><code>book_name </code><code>=</code> <code>soup.find(</code><code>'title'</code><code>).string</code>
<code> </code><code>path </code><code>=</code> <code>'./'</code> <code>+</code> <code>get_legal_window_file_name(book_name) </code><code>+</code> <code>'.txt'</code>
<code> </code><code>links </code><code>=</code> <code>[]</code>
<code> </code><code>#提取所有章節的連結</code>
<code> </code><code>for</code> <code>tmp </code><code>in</code> <code>soup.find_all(</code><code>'tbody'</code><code>):</code>
<code> </code><code>if</code> <code>len</code><code>(tmp.find_all(</code><code>'tr'</code><code>)) > </code><code>1</code> <code>:</code>
<code> </code><code>all_link </code><code>=</code> <code>tmp.find_all(</code><code>'a'</code><code>)</code>
<code> </code><code>if</code> <code>not</code> <code>all_link </code><code>is</code> <code>None</code><code>:</code>
<code> </code><code>links.extend(all_link)</code>
<code> </code><code>if</code> <code>book_url.endswith(</code><code>'.html'</code><code>):</code>
<code> </code><code>parent_url </code><code>=</code> <code>book_url[</code><code>0</code><code>:book_url.rindex(</code><code>'/'</code><code>) </code><code>+</code> <code>1</code><code>]</code>
<code> </code><code>parent_url </code><code>=</code> <code>book_url</code>
<code> </code><code>with </code><code>open</code><code>(path, </code><code>'w'</code><code>, encoding</code><code>=</code><code>"utf-8"</code><code>) as f:</code>
<code> </code><code>for</code> <code>link </code><code>in</code> <code>links:</code>
<code> </code><code># 作家連結,忽略</code>
<code> </code><code>if</code> <code>not</code> <code>writer_link_pattern.match(link[</code><code>'href'</code><code>]) </code><code>is</code> <code>None</code><code>:</code>
<code> </code><code>continue</code>
<code> </code>
<code> </code><code>print</code><code>(</code><code>'\n'</code><code>, link.string)</code>
<code> </code><code>url </code><code>=</code> <code>parent_url </code><code>+</code> <code>link[</code><code>'href'</code><code>]</code>
<code> </code><code>print</code><code>(url)</code>
<code> </code><code>response </code><code>=</code> <code>HttpClient.make_request(url)</code>
<code> </code><code>chapter_soup </code><code>=</code> <code>make_soup(response.content)</code>
<code> </code><code>chapter_name </code><code>=</code> <code>find_title(chapter_soup)</code>
<code> </code><code># 章節标題</code>
<code> </code><code>f.write(</code><code>'\n\n'</code><code>)</code>
<code> </code><code>f.write(chapter_name)</code>
<code> </code><code># 章節内容</code>
<code> </code><code>f.write(chapter_soup.find(</code><code>'p'</code><code>).get_text().replace(</code><code>'<br/>'</code><code>, ''))</code>
<code># for p in chapter_soup.find('p').contents:</code>
<code># if p == '<br>':</code>
<code># f.write('\n')</code>
<code># elif p is NavigableString:</code>
<code># f.write(p)</code>
<code># elif p is Tag:</code>
<code># f.write(p.string)</code>
<code> </code>
<code> </code><code>f.flush()</code>
<code> </code><code>print</code><code>(</code><code>'電子書已成功儲存: '</code><code>, path)</code>
遇到的問題:
不同的書(甚至章節)标題内容、字型(h1,h2...)、标簽結構都不同;
應該是為了增加爬取的難度吧,不過隻能針對遇到的問題進行分析、解決;
本文轉自 breezy_yuan 51CTO部落格,原文連結:http://blog.51cto.com/lbrant/1688440,如需轉載請自行聯系原作者