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