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