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