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