|
本帖最后由 bt4baidu 于 2015-11-22 10:08 编辑 # H: a$ U3 }0 ~
' @2 b$ M" j! ]+ B6 n5 _
这篇文章主要是给计算机小白和初学者扫盲。
6 Z$ z/ A# Z0 Z6 Z) X& O本人尽量写得浅显一点, 希望完全没接触过计算机编程的文科生也可以看懂。: P) v3 q! E" ?+ V" h8 m1 t
只讲原理和思路, 具体的编程语言、语法之类的问题自己找资料解决,网上到处都是。4 z% C: p* q% ^+ g& \6 f" V; _/ u+ q
- @0 ^! M' j0 V
一、计算机的两个终极哲学问题7 Y+ L/ g8 D( Q) P a
1936年,图灵在他的重要论文《论可计算数及其在判定问题上的应用》里,提出著名的“图灵机”的设想。3 \. r: x8 P$ M% ]& M1 a6 A
图灵机被公认为现代计算机的原型,它的工作原理简单来说是这样的:
6 Q! J3 @- b1 ^+ r8 M: J设想一条无限长的纸带,上面分成了一个个的小方格,方格有两种:空白的和上面有“—”的;: W: M J) m) J Y) f2 R: l
机器读入纸带上的方格信息,根据这些信息, 结合自己的内部状态查找程序表,输出计算结果。
% s7 \1 O$ i# j/ A2 {0 T方格信息代表了解决某一问题所需要的步骤,这样进行下去,就可以模拟人类的任何计算过程。
% H b; @% C3 V, U% I0 v“纸带方格”代表外部输入,“内部状态查找程序表”代表算法——也就是程序,要靠人来写的。" P6 X. f* ?% Z
! L! g7 m: X; f" P0 E那么要写出程序,立即就会发现不得不解决两个问题:, h; s; j% Z" g X5 Z! ?% I
1、怎么知道机器当前读入的是哪个方格?怎么读到具体某一个方格?也就是寻址。
. q6 {! n. h+ `1 y. O2、怎么把两种方格区分开?也就是特征识别。
) v' H2 x. f( `/ U# u8 d这两个问题,就是计算机的终极哲学问题。
& J5 a& D5 R V& ?9 R理论上,所有的计算机程序问题都可以逐步分解下去,最终分解为这两个基本问题。# x% a$ I3 Z6 ^. o
下面的讲解也会以这两个问题为核心展开。
( D6 h% P1 n, a* |% |, M: U+ j
; q( m: L8 ]5 H4 B' hBTW, 如果你能想通这两个问题,遇到编程问题都可以这样子分解一下,把自己想象成一台图灵机,
4 u1 ?' p( V( @% J——所谓“采用程序化思维”,也就相当于打通了任督二脉,立即具有了至少10年的编程内功。; s9 V/ V* J& O6 k2 X# B8 t
所谓编程,本质上就是一种读取、存放、组织、区分数据,然后按照具体业务计算出结果的活动。
; w [5 l2 z. Y) `前者是核心,“我强烈建议围绕着数据来设计代码,而不是反其道而行之...坏程序员总是担心他们的代码,4 O9 n4 d% ?' A: v6 g) O1 v
而优秀的程序员则会担心数据结构和它们之间的关系。”——Linus曰。, a6 P" ]: z! b
具体的招式,也就是某种具体编程语言的语法,花个半天功夫就能学会的。
) J7 Q8 n2 _+ L' T" W4 M/ ]
: L' G% \- ]! n/ x" R不要觉得自己上学时学的不是这个,or文科生,就不行。
& g5 ]1 U7 Z- q江民杀毒软件大家想必都听说过。. V. | e; `+ v. t
创始人王江民同志,初中毕业,38岁才开始自学计算机,不出几年,就成为中国最早的反病毒专家。
+ B9 g7 B$ L) U- E6 C& G咱不奢望成为专家,写写程序总还是可以的吧?* c9 Z; g: U* S: Z* T
# f! n) v. O2 B7 J7 U* _
二、采用何种编程语言! z- {1 F0 V& v6 I4 `4 t
上面已经说过,存放、读取、组织、区分数据是编程的核心问题。7 a8 V1 t# h$ d) } d( y- v. @7 p
显然,能够方便的进行上述四种活动的编程语言就是最好用、最易上手的编程语言。
]1 q, D4 a( c! I抓网站,恐怕没有哪种语言比Python更方便。3 g3 X1 D8 j# f
当然,你要愿意,用C语言也不是不可以,不过可不是那么容易上手,
2 X8 l& v9 S0 ^( C* |计算机专业的学生,有些到了大四毕业居然还搞不清何为指针、何为引用...这些家伙还是趁早转行,' ]& @* J0 P) B* [9 }
没有慧根就别吃这碗饭。# Y" z9 s) D5 b0 c' ~. T, T
/ s' I3 }8 G9 R% c1 q9 q$ J7 x三、网站抓取技术( y7 D0 L+ E, _" }
1、下载某一个网页,提取其内容5 U$ u0 _: D' u2 H0 y
以前写过一篇,就不重复了。参考:
) r) h- H! @* R6 `- y0 \用一个简单的例子讲讲怎样从网站上扒数据6 ], f" s, r8 m9 C1 ^
5 W, m+ O5 F0 H1 p: N: J2、寻址问题$ H5 A2 Z3 o9 T/ h5 c; d8 i! h
下载网页,自然首先要知道网址,也就是东西放在哪儿。
7 N5 O% o Q7 {9 u. x, z" z如果事先有个单词总表,那是最简单不过,立即就可以根据网站的网址规则拼出来。
- b2 P) i! Z+ X5 n) Y7 ]但是大部分在线词典,到底收了多少单词,事先是完全不知道的,- J- S& O) Y& g0 X9 W$ e" G
要把单词弄全,就要想办法得到每个单词的网址。
8 d/ f/ z, j! A! i. G总结各主流词典网站,大概可以分为这么几类:6 o4 C+ \5 _+ r# _' }+ z( [
I. 事先有单词总表
/ ~- o) j, G% S1 D2 F比如http://www.vocabulary.com就是这种类型。
1 _# b- f k7 h! M它是在wordnet3.0的基础上编纂的,直接用wordnet3.0的词汇表拼网址就可以。
; V5 p: I9 v7 G c" H) d& Q; u5 Y
5 Q+ M" z+ d' |& k- O* rII. 网站有索引页面
% g% x9 k% _& }# o4 n4 L- g! u如:6 S$ S8 N* C$ B$ L
OALD(http://www.oxfordlearnersdictionaries.com/)
- S+ O2 O- i, w4 G: o* _ g2 k; L它的索引页在 http://www.oxfordlearnersdictionaries.com/browse/english/
$ p" u1 B% z$ ^* [8 vLDOCE(http://global.longmandictionaries.com/)1 l% k* V$ z, u# V: f1 z0 g A5 ?" M
采用框架结构,左侧边栏就是索引页
% a. i$ k% N, j- |# NMWC(http://www.merriam-webster.com)
; c$ j! m" P- D# V9 y$ x$ Z6 h N索引页在 http://www.merriam-webster.com/browse/dictionary/
; ?: c8 B" Z9 v p. K) u+ Z- `等等. {3 ]+ h- B# I' A* f1 k
这类也容易搞,思路是先从索引页得到单词表和网址,再一个个下载。! j' T- w" W7 ~& f8 c
( g+ A4 A/ T1 j* Y8 |7 p, v- urls = []9 X9 ]8 m8 ~: ]4 @; x3 e4 g% Z6 y
- for someindex in indexs: # 循环所有索引页
2 t/ X2 \8 {* ^- D: } - browseurl = ''.join(['http://somewebsite.com/', someindex])1 F% K5 C' l4 s) L6 U/ [% ^2 x
- browsepage = getpage(browseurl) # 下载索引页面/ z1 G ]& g# W. v9 Q) [0 c3 V, Q
- target = SoupStrainer('sometag', class_='target') # 抠出放单词链接的区域$ C( N& j9 c- f# E% j
- bs = BeautifulSoup(browsepage, parse_only=target); R/ }0 r. I% L
- if bs:* o+ V, K( c9 E: O0 L2 U8 R
- for a in bs.find_all('a'):% ^: V9 r& W7 d* o8 h, t8 Q% f, W
- urls.append((a.string, a['href'])) # 取得该索引页上全部单词及链接. Q( f+ ~5 k# a
- 然后:; i: B# c7 q* B# v- r+ q; H
- for url in urls: # 循环所有单词. e' g G4 _) G& ?0 b: |
- wordpage = getpage(url) # 下载单词页面
: j7 ?" \ L0 R8 R7 _
复制代码 2 j5 l. k. t) m, _. C0 m
% V5 S2 E' w1 a) y: {III. 索引页和单词释义一体型网站
! v) ^ K( B ^. G; B如:Online Etymology(http://www.etymonline.com/)' b# D4 _9 x6 H6 g. C- T, x3 I
和上述II.处理方式相同,在循环索引页的过程中把单词抠出来即可& D ~0 j( z( k* {# `
# C2 @! S. |5 Y4 e$ x- for someindex in indexs: # 循环所有索引页; O% Y6 J" s, C( C, G) L+ H2 M) X
- browseurl = ''.join(['http://somewebsite.com/', someindex])
- A( C. v! }5 G- E - page = getpage(browseurl) # 下载页面
, I+ ?& l" G! [$ V - target = SoupStrainer('sometag', class_='target') # 抠出放单词的区域
/ @$ V( Y* K1 h" m3 E, w+ C - bs = BeautifulSoup(page, parse_only=target)
' N/ K3 \, i Y: O( L3 v& T( G - for tag in bs.find_all(target): # 循环抠出单词
8 {+ ~: W& J* K( N: u, L - worddefine = getworddefine(tag)% T! @; N1 i. O( m6 J1 |+ k
复制代码 " c+ {; Z! b* E5 _9 _ ~
% T6 N& B2 ^; h& X. q# u; iIV. 片断索引型网站
/ I# L6 n# L9 j: M, F# v. t如:+ j5 `& f- `) s& m7 Q1 ~7 v
ODE(http://www.oxforddictionaries.com/)
" E& b: \9 @4 ]4 Y+ o# M( J! T4 C$ k每查一个单词,右侧边栏有个Nearby words
! H$ W3 F! m: g( P6 jRHD(http://dictionary.reference.com/)9 `% Y" r$ }9 ]" J7 r) f9 ` @* X
右侧边栏有Nearby words2 _* ?9 q: M, I
CALD(http://dictionary.cambridge.org/), |7 z6 R3 D( m- T
在页面的最下面有个Browse栏,给出前后相邻的单词* \7 d8 H" F) ^3 q
这类网站没有总索引,只好利用它的Nearby栏。# t7 \0 _- C, P$ F+ [* g7 D e1 D) f, K
思路是从第一个单词(一般为‘a’或者符号数字之类的)开始抓,& O2 [% @: {2 j+ _
每抓一个单词,同时得到下一个单词的网址,直到最后一个单词结束(一般为‘zzz’什么的)
8 a0 h) [: l! v( ~- ' V- ?0 R/ `, n: |% b+ t
- cur = 'a'; w% ~0 C: v4 r5 m1 a
- end = 'z'+ ]1 T# h9 b) D6 h9 j4 ^$ A
- nexturl = ''.join(['http://somewebsite.com/', cur])4 X9 @! h% e' T' m
- while cur!=end and nexturl:0 Y" k: r* u9 Y' Y5 ^. }
- page = getpage(nexturl) # 下载单词页面0 t: A2 Y/ e" s3 i4 K
- worddefine, cur, nexturl = getword(page) # 得到本单词释义、下一个单词及其链接7 {: c. Q6 f& l( T2 D9 N4 A4 G4 L
复制代码 3 `3 v0 {- m$ G
) Y4 u/ C( K3 F% M
V. 完全没有任何索引,那就没法子了
j% M( V4 U/ ?" p! R当然穷举算是一个办法,自己搞一个庞大的单词表,然后按I.的步骤处理
: A& S) X. N, B2 W/ v9 Q4 ?8 y' D理论上也是可以的,就是效率差一点;$ W% j: T* p* Q8 A: s
另外各家新词收录情况不一,有些词组、短语拼法也不太一致,单词表准备得不充分就没法完全网罗。6 R" m5 _# J- o: h% u2 E
" ]" \+ e0 h/ r9 k9 U7 v
3、提高下载效率9 J& b/ u. f# Y( F
I. 多进程
2 s! f9 C' @3 c9 U上面写的都是伪代码,也就是简单示范一下处理流程,直接写个循环了事。
3 |+ S' m/ u8 _6 Z实际抓网站时,这么做效率显然是非常低的。
2 A7 w4 ~' d8 P; K8 M假如有十万个单词,每个单词需要1秒,循环十万次就是差不多28小时,要花掉一天,
' q0 a$ n5 V- O1 k, Q- Q9 O有些网站还经常抽风,半分钟下载不了一个单词,那就更慢。 U; r+ ~8 g V* S X7 {
假如在这段时间内,你家猫咪把电源插头给挠掉,或者键盘被女秘书不小心坐到了呢?1 {; l2 j1 W1 q4 I6 v* u; O
要速战速决,就得开多进程。) a3 C$ f* m! {9 e: `9 o
同样十万个单词,分成25个进程下,也就是28/25=1个多小时。
: q, C0 `+ q$ g& e' D' c3 ]再开多一点呢?岂不更快。。。那样硬盘就转不动了,所以也是有极限的,要看PC的配置。
7 k* n' D+ }- H B% E# O7 C: M在Python里开多进程,同样十分简单,5 [; |: [$ }3 ~% c* q
- 3 [1 e, x0 y& F5 K! {8 U
- from multiprocessing import Pool( `3 C* O0 n: K/ L0 J
- pool = Pool(25) # 开25个进程# Z+ M* A& O$ E; [9 K# \
- pool.map(downloadloop, args) # downloadloop是下载函数,args是其参数
) p; F+ Q/ Q6 h" m0 A
复制代码
; Y0 ~5 m1 d6 O r) ]这就搞定了。
" }; B4 B, D8 W
0 L7 T) c( g) o l' d4 h4 I/ @对于上述I.~III.,包括V.,分块比较容易,无非是把一个大数组分成25份,$ j- _2 Y; C5 f8 W! j& ] {- y5 K
关于IV.,事先没有单词总表,就只好采用区间的概念,
& \& K; g4 F+ ~6 b' C比如('a', 'b'), ('b', 'c')。。。这样划分若干个区间下载
- t4 q/ @/ c0 L- V( b$ X# g; j
8 f8 v" H! A" v! D4 H初学编程的人,一碰到进程、线程,常常有种畏惧感,
2 v1 ?$ z' }: ^: V% w! I% {2 I看到同步锁、共享内存、信号量什么的顿时觉得头大。) O$ F% m( M+ K& P7 c) G1 e
其实没什么好怕的,这是个寻址问题,关键是搞清楚它的内存空间构造是怎样的,
2 ~* [! U& C8 r3 ^& f \2 ]其中涉及到一点操作系统、读写互斥、原子操作的概念,找相关的书了解一下即可,没有特别难以理解的。
" \+ m4 x+ S$ l/ u7 v6 G+ j2 z9 Z# g2 }- i+ Z8 I* ^
II. 断点续传' m* V2 I8 ?" V/ t7 \ {' E, i# [
事情永远不是那么完美的,网络连接随时有可能中断,网站可能存在瑕疵、死链。0 Z* e- Z* C* ^# B
所以下载程序也要有点容错的功能,最好莫过于可以自行从中断处恢复,完全无需人工干预;
( q5 d6 |. K6 }0 {' a6 Z即便无法自行恢复,也得容易手工处理,不然可有的烦了。
, _. h9 w/ y# n/ b d! E& `这也是个寻址问题:关键是搞清楚从什么地方断的,把它标记下来;循环检测没下完的区块,从中断处接着下,
- a4 }% M7 P7 x9 ^% E2 v, v& I0 g直到所有区块下完。5 ?4 i1 s$ p$ w- _
7 q5 y7 o& {2 H8 k! p3 _- def fetch_a_word(part, word, url, data): # 下载一个单词5 p# ]% ~* x" G- k
- word_define, failed = get_a_word_from_website(word, url)
3 U! V# K9 Q0 d6 ?0 d - if failed:2 A% B4 @. Y* J4 x
- dump_failed_word(part) # 输出下载失败的单词及网址
3 O! b. p* s% i" p l7 ?' @+ r& m - return False
2 e: w }' R( u1 @1 t7 C - else:
/ i5 H, C* y" \; X% w/ R* {* v - data.append(word_define) # 保存下载成功的单词数据: m4 ~+ U* d7 Y
- return True" Z1 E7 B0 H# x2 {+ u Z
7 y% E7 Y2 z# D! Z: u# n- o- def download(part): # 下载一个区块# s& k1 ~3 N' }3 e. Y/ p0 N
- words = getwordlist(part) # 读取单词总表9 e, ~0 {- d8 o% o" ~+ I
- if hasfailed(part):
3 }/ n6 j" z% ?7 e6 N - word, url = read_failed_word(part) # 读取前次下载失败的单词及网址
+ Z2 E5 o' I) f, i! _6 ^1 L - else:
8 W i+ e/ r! v H+ y5 N - word, url = words[0] # 首次从头下载8 }, B! \$ [- n
- data = [] # 用来存放单词定义% m& |3 f# L5 P/ b* N; L! q
- while not_end(words): # 循环下载
; O7 D7 j0 e5 {4 f( c - if not fetch_a_word(part, word, url, data):
# {4 \4 R, d) e) [ - failed = True
& T+ G4 I0 x" A) T - break
# s f% t% f3 D# ~( M3 ^& d - else:
! C; o r) G0 k3 [0 V - word, url = get_next_word(words) # 准备下一个单词及其网址
/ {8 B: g8 ^1 L5 I - if failed:
0 F8 a) A+ e6 g v' @/ x - suffix = '.part'
" s$ i, E4 ]2 _( c& ~ - dump_data(data, suffix) # 输出下载成功的单词,若因下载失败中断,文件名加后缀'.part'/ _1 m9 f1 A4 ~+ C% v) L
4 S8 I- ?' M8 Q7 H- def isfinished(part) : # 判断某区块是否下载完成9 e+ b0 D' `. p7 V
- if is_data_file_exists(''.join([path, part])): # 通过检查数据文件有没有生成来判断 I5 t8 |& \& _2 k/ J
- return True; |, }6 d3 S5 y& N8 N& o$ c
- else:/ G/ u/ A6 D K% z3 q+ B; [" L
- return False
4 h0 P) |: h6 ~. a4 E" h
: n D+ @) \- G* k" a5 L2 ^7 N- def downloadloop(): # 循环检测未下完的区块4 U1 m; `2 o3 H! A& ~. \
- finished = 0
G/ e- N- K% \7 D - while not finished:. f* o- ~$ L) I2 f- H8 o
- nf = [] # 没下完的区块% K; z7 _. e. w. p* _' N
- for part in parts:
) j4 F1 N' U. y) o' r: ^4 S2 M% D - if not isfinished(part):) { U8 ?, s! s2 p: d5 n
- nf.append(part)
$ Q7 X. v3 v) l# ?7 [6 B6 \ - finished = not nf' O7 U6 w' I0 } D% I
- for part in nf:+ z6 ^+ d& p# M, {4 y4 c [/ }8 ]
- download(part)$ g! y7 @- ~! q
复制代码 5 I7 C! R) T4 S% R& o+ O( H3 P) Y
6 ?( j; w! j: r0 T' |% M! H! N! N
III. 高速下载网页的小技巧
( N, h! v5 }: I: v. R$ K9 TPython里面有三个库都可以用来下载网页:urllib2、urllib3和requests。
0 y% V6 @# t9 O, H其中urllib2是Python原生的,urllib3和requests为第三方库。3 d5 W( j; T7 S$ U2 Z4 U! P
(似乎Python3已经把urllib3收编为正规军了)
! ^3 h; C& ^! K: E' |# f这三个库有什么区别呢?4 M) ?. B6 _+ F
形象点说,urllib2相当于去别人家“拿”东西,开门只拿一件,然后关上门,再开门拿下一件的家伙。
8 M2 T7 P$ B. |, L' g再笨的贼也没有这么干的,不停地开、关门太浪费时间,也容易招警察;同样,频繁连接也会网站被封IP,& y. |. ^/ V" K! z1 D" o! u
所以urllib3在urllib2基础上加了一个HTTP连接池,保持连接不中断,打开门以后一次拿个够,然后关门走人。' J ~ B! w9 V0 ~" \1 _6 H
但是urllib3有个问题,它不支持cookie,所以无法保存用户信息,遇到需要登录的网站就没辙了。
$ t# w% o" I% C& ]8 g& u' C6 |这时候就该轮到requests出场。requests在urllib3的基础上又进化了一步,它可以通过session来保存用户信息,3 O+ a) `8 W% y
通吃一切网站。
# ?& Q- s* `; g; M" k3 g所以你完全可以只用requests,忽略另外两个。不过我一般习惯用urllib3,只在需要登录的时候才用requests。
. ]8 q( O& f, K9 g5 Q G# Z7 r1 [' q这仨库的用法都非常简单, 两个第三方库都有齐全的文档可供随时参考,虽然大多数功能都用不到:
% Y/ x/ N, X( j' L$ bhttp://urllib3.readthedocs.org/en/latest/! z6 ~ X* |, X5 V% R
http://docs.python-requests.org/en/latest/:
2 z4 G3 P2 e# u- , I7 k! c7 p8 z: U" G
- #urllib2
8 t3 E! R' \2 N! V" u - import urllib2
! W- f) I: h$ m- y - def getpage(url):2 j9 n" j( F- v
- req = urllib2.Request(url)* a" d9 ?/ O& m
- response = urllib2.urlopen(req)
( }1 W+ K7 h6 @: Y0 g% B - page = response.read()
4 [8 Y% x* N4 L/ X - . {( Z& g2 w k5 V5 i
- #urllib3, I. k0 R: k4 ]8 U9 |
- from urllib3 import PoolManager
( F1 j" b6 ~# |: m, ] - http = PoolManager()
6 T1 w9 T! a8 f1 ]$ W0 S4 w8 G - def getpage(http, url):; Z, F: L. ] Q8 S: c
- r = http.request('GET', url): m8 |4 ~& g3 A9 m' c
- if r.status == 200:
" o+ T, A1 m" T - return r.data. z* a W% a/ |8 f1 l8 V( e
- else:1 \* z3 A0 K+ a: L; _
- return None. g& H" q) b' S8 m: L3 E6 f9 E
- $ F8 g+ @- T4 N9 \1 A, P& }: Y5 h2 K
- #requests7 ^' j9 }% k+ C
- import requests9 b( [7 ~+ I& s' N4 }
- session = requests.Session(), T9 q" n2 v! w: k
- def getpage(session, url):
h: l" D# E. J! H/ d - r = session.get(url, timeout=10)1 ?9 F* h. o, b+ I2 O- N
- if r.status == 200:5 R8 m& \" O2 ~; n) w% m
- return r.content& z: [# M% }4 }6 ]% Q, |
- else:
0 _9 R( |/ ]3 h: f7 N% g* ] - return None
* A( }( s* I/ |3 J7 {8 m8 m, b
复制代码 9 D; ?+ e2 [4 z" F9 l& l3 o( O: [
四、后期制作4 e$ _9 u" U4 y* q/ l+ K
1、文本处理,是个特征识别问题。+ z1 a! _0 G5 O! U8 S$ o8 l
本质上是找到满足某种模式的一串数据,按一定的规则转换成另一种模式。( O4 |& N2 d+ [+ n( I! B* W1 _
当前的大热门:生物识别(人脸、指纹、静脉、虹膜。。。)、语音/摄像头输入(智能家电、自动驾驶。。。)
5 x, V. h6 ~" _; e都涉及到特征识别问题。
8 \0 [, T: T9 ^8 ~. t& X% k相比这些高难度动作,文本处理算是比较简单、基础。
; X6 A/ U, v/ Y" I% Q1 |+ G2 uPython里常用的文本处理技术:正则表达式、BeatifulSoup、lxml
8 S" k1 f- E0 a8 v+ k. U: `& ]正则表达式非常强大,但没法处理递归嵌套的标签型数据
1 }7 ]' ?& {8 h' A. i9 D- o3 E+ u5 f(如:<div>第1层<div>第2层<div>第3层</div></div>...</div>,这已经不属于正则文法的范畴);( }1 }! U0 _6 r2 n
BeatifulSoup/lxml可以处理嵌套的标签型数据,普通文本则无法处理。3 r/ b7 E" q. w# @ [5 p( s
所以常常要结合使用。1 V& g3 E; G4 M: _ W" i
这些难度都不大,关键是胆大心细、思维缜密,不厌其烦,慢工出细活。, O2 p& [0 f% Q9 b% b+ E+ R; D% b& {
7 x j/ n3 O9 Y$ }2、排版
6 X& [4 s# S) W8 P$ EHTML、CSS的基础知识:
' N7 m( X: }; q# I' K4 Xhttp://www.w3school.com.cn/html/index.asp
4 a x3 E3 u3 v4 xhttp://www.w3school.com.cn/css/index.asp/ ?. d. d8 P" \* s) q0 |& `- ~
http://www.w3school.com.cn/css3/index.asp
+ O8 |# l. x, x# ]+ J$ D非常系统、非常全面。0 f/ V: j% j# F- d5 ~" z6 V
排版词典需要用到的HTML/CSS知识并不太多,遇到问题参考上述网站即可。
- b1 ^" O8 M. h1 \( Y/ i
[6 f& E1 Z2 Q# N! _1 m9 {- j# E五、结语( E/ h& |# {( s/ e( T+ G8 M" g
花点时间写个科普文,主要是考虑到确实有些文科同学or计算机小白想制作词典,但没有思路,无从下手。1 \/ W9 H3 ?( M @/ H
所谓术业有专攻,为学有先后,总结一点经验分享出来,也算是对社会做点贡献——
# @7 Q, o% B( ^; P" y8 H& g大家有个切实可行的方法参照,不至于绕太多弯路,浪费太多时间,从而节约了社会成本。 h, a7 d* Y+ d" Z, s
9 }2 O$ H0 s' t4 j9 [打算做万年伸手党的同学,本人也没想过要鼓动你们,继续做伸手党好了,热心人还是挺多的,时常有不错的新作发布。
: C# B. D) i3 d2 i; F9 Y% w1 i
' L7 B$ n4 m- O) T7 }6 W只是拜托不要打扰别人,真想要就自己动手。; R8 p+ a& i0 M f4 j& T' U6 k
尤其不要抱着“你手熟,水平高,做得比我快”的想法,觉得找别人做词典就特别理直气壮、理所当然。$ m; e5 R0 K, V6 u0 Q
水平再高也要花时间;同时,水平高也意味着其单位时间的价值要超过水平低的人。0 H V! i6 @4 M; s
虽然每个人都觉得自己至高无上,应当受到别人重视,! ^5 w! W! \9 P
其实“在你做出惊天动地的大事、拥有巨大名声之前,你在别人眼里就是个屁”——Bill Gates曰; n: B) P% v- N1 @4 v
3 c3 h0 A6 A$ L4 Q
+ V) v- z% O5 q/ s
========. L$ h P% u6 P+ p
六、拾遗
+ w9 ^4 l. v5 ?: D a关于上述IV. 片断索引型网站,有坛友指出ODE、RHU等都有索引页,因此可以归到第II.类
0 p7 y5 N4 `1 P/ T确实如此
4 n* f- q/ S9 Q1 O, e$ i4 b不过这里只是举例而已,不用太较真啦
. ^8 H F2 u! f' J* _. u# s6 f实际操作过程中,由于网站可能存在索引不全、死链、交叉跳转及数据瑕疵,往往要将II.和IV. 的方法结合起来用,否则不是抓重就是抓漏: K6 N' l9 M6 p' Z2 \: j5 D
这种综合性的抓取方法,本人称之为单词表密集轰炸+广度扩展法。# \( @5 `" B% \. n, H
即,4 h) S w% a2 w6 u; K$ m
第一轮:先从索引页面获取全部的词头(集合A),再用这些词头去网站下载单词,同时提取每个单词页面里指向其它单词的链接(集合B)' Z9 V6 n0 P3 a) l8 t& @5 z" \
第二轮:从集合B里删除已在集合A里的词头,得集合C;再用这个集合C里的词头去下载单词,并提取每个页面里的链接(集合D)
) ?7 [' B8 @- @第三轮:从集合D里删除已在集合A和B的并集里的词头,然后重复第二轮的后几步动作
' x4 b9 G4 c8 f# U' j。。。
1 V1 ?- T/ b8 R; t2 j直到无法提取到新链接时,结束下载。大部分时候,第二轮结束时就已经提取不到新链接(即集合D为空)
: {2 {1 P/ V6 g5 N$ V3 M% s最近新做的RHU、CED、WBD,均是采用这种方法,速度快,容错性强,效果极好。
* k, G0 l. Q0 m7 V形象点说,这种方法相当于草原上先有若干个着火点,这些着火点会把其周围的草地点着,最终烧光整片草原。+ W" C9 p+ d0 r& y; h
因为一开始着火点就已经比较多(索引页的大篇单词表),所以会烧得非常快、非常完整。
3 b5 C. a: ]3 t" b* s. z& m |
评分
-
4
查看全部评分
-
|