#!/usr/bin/env python * P* {+ t( G' O" p$ z# -*- coding:utf-8 -*- 2 }1 y& I- p, x""" / u1 K+ Q+ O3 Z2 ~: YPython爬虫,抓取一卡通相关企业信息 , Q& n3 u$ K9 J" a: }+ Z# mAnthor: yangyongzhen 3 s5 S% D- }9 V2 ` J2 IVersion: 0.0.2 * A0 k+ a) f1 G5 C" a5 @! U4 cDate: 2014-12-14 ; U7 b! G, _. N3 f- LLanguage: Python2.7.52 k/ `, J* y* e7 `$ l
Editor: Sublime Text2 9 H0 Y$ l, M" { }5 l) L""" * l' N/ J2 r' M, z- F& ^( M : i0 t# U$ ]: eimport urllib2, re, string3 P! e$ }. E9 R F8 ?' T; \
import threading, Queue, time 5 f; w( E; z7 R- n+ \; T; Iimport sys " i* }+ m$ ~8 @; s- r0 ]# {6 pimport os s- B. D; H m1 t. B1 X
from bs4 import BeautifulSoup* B* _" z1 U. H/ g( x. J
#from pprint import pprint, V6 l& R( b- M9 S
8 @* r) |9 V9 j) O+ k* z
reload(sys) 3 _% }. [1 F+ b7 isys.setdefaultencoding('utf8')7 q8 Q' [% j, M$ \0 N5 ^7 [0 @
_DATA = []+ R8 Q! h1 j6 O3 j! E- K' p
FILE_LOCK = threading.Lock() % g: W& _, D. [* n- pSHARE_Q = Queue.Queue() #构造一个不限制大小的的队列# A' _, c/ \8 H9 R+ l' s
_WORKER_THREAD_NUM = 3 #设置线程的个数% R6 y4 F* w0 V5 i
U9 b% f1 m( V8 t3 a) x2 t& d_Num = 0 #总条数 & l5 I3 K @- J' l' |4 Yclass MyThread(threading.Thread) :" {, k6 a# D- g& L6 [
* h- d) W# E* o( y. A5 O7 v def __init__(self, func,num) : 4 ]% u! [1 T" d, n6 a* S4 P" B super(MyThread, self).__init__() #调用父类的构造函数 [1 F: R$ m& T/ U9 k9 I2 V/ | p
self.func = func #传入线程函数逻辑: U# M! h1 G7 L0 }! f
self.thread_num = num ; `* ~3 p( b5 m' f def run(self) : * f- ^7 D# @* G$ \: M& u9 t self.func()( V+ D% [ [ N# R$ @2 _- `; f
#print u'线程ID:',self.thread_num 6 A) D, Z! j# T i 6 i4 k, P( f1 V1 N/ ~def worker() : . K" Q. a, @$ y9 ~' w5 C global SHARE_Q/ M8 ^5 ?! z, a; R/ u% B
while not SHARE_Q.empty(): 6 k: J* l3 [9 W' x/ C! ~ url = SHARE_Q.get() #获得任务6 ?# O$ v I; H
my_page = get_page(url)6 h' j4 t8 N) O: E. f- a
find_data(my_page) #获得当前页面的数据 % L8 r- j% T4 G+ c# q S+ O #write_into_file(temp_data) / R z; Z! Y8 l' W7 A P9 S time.sleep(1). P$ [& }. g: m+ \! S9 ~ c
SHARE_Q.task_done()8 _0 L, | v3 }
4 z7 q3 q; R' ddef get_page(url) :) |+ Q) Y$ k, X- ]/ C
""" 3 C% G! Z: G9 W" k" o* Q 根据所给的url爬取网页HTML ( G# Y. w! ^* \$ C6 g k Args: $ I3 T1 M- B- p6 _1 N
url: 表示当前要爬取页面的url' R/ o( l/ ]. { g. X
Returns:) ?2 M) q# l d9 R3 u& j7 s
返回抓取到整个页面的HTML(unicode编码) 0 y% D" E i* S. P9 O- l5 N; ]2 F7 G1 B Raises:0 m i2 t9 y9 w5 T% O) w
URLError:url引发的异常( A0 d2 B6 X" `5 s0 K% L. T! A: q
"""/ J" Y& L' |! o0 W3 a
try :2 v2 Q+ B- X. Q( R9 I+ j
html = urllib2.urlopen(url).read()$ l* e- J4 @# r( ]& k
my_page = html.decode("gbk",'ignore') W7 F7 Q3 q* R. g #my_page = unicode(html,'utf-8','ignore').encode('utf-8','ignore') 0 n. y8 [% \' | #my_page = urllib2.urlopen(url).read().decode("utf8")0 V8 ` n) ?2 q! j% F. G+ I+ j' j
except urllib2.URLError, e : Y! z: t5 a/ H) e; `0 b: ~ S# J( R if hasattr(e, "code"):+ G1 l$ |/ N7 e" U
print "The server couldn't fulfill the request."; c, R3 Q: i' ^! i* {
print "Error code: %s" % e.code + K: p5 e, R: x& a! a elif hasattr(e, "reason"): ?4 Y" \3 A- S* Q B( v
print "We failed to reach a server. Please check your url and read the Reason" 8 M1 t! |; _# I; b; x% k print "Reason: %s" % e.reason) p7 ?4 D' u/ [) ?/ ^
return my_page " N5 W% S% k; {9 R1 F0 w: w# u n8 G; ?9 v1 q# s4 V' W
def find_data(my_page) : $ d7 i+ i5 L; p """7 j. q# ~& D( F; W
通过返回的整个网页HTML, 正则匹配名称: ]$ s2 k% w2 }" y( ^
h. p' O- @- d* @: V) `0 q3 C( M
Args: 7 t& b0 f4 y# G0 } my_page: 传入页面的HTML文本用于正则匹配 * f. g* `! A9 x+ p T, t# G+ f """0 X6 c; o( @3 A5 J: h2 F
global _Num/ V# K' G, u" o( w
temp_data = [] " u6 _# H6 O7 s/ l" ]+ u! n4 o items = BeautifulSoup(my_page).find_all("div", style="width:96%;margin:10px;border-bottom:1px #CCC dashed;padding-bottom:10px;")/ i! M7 D8 N8 p0 t
for index, item in enumerate(items) : 6 _$ o. ]! Y `( g$ m. @: g #print item - v& J2 O" D2 ?& C #print item.h1 1 z7 @- t! j+ ?0 D1 j* |; \ #print h.group()! y. T. ]/ _( b( l6 O" X% B
#temp_data.append(item)4 k9 i3 d8 j/ h; v8 H/ D4 z
#print item.find(re.compile("^a")) ' I& p" r* k/ V% {: s$ W2 B href = item.find(re.compile("^a"))8 |) ]3 q' `* @
#soup = BeautifulSoup(item), v6 O( Q, P% \( X8 `4 d' b4 j/ m
#公司名称" D7 b% n& ]" n; F0 q h
if item.a: - l; J$ H6 A; B* ` data = item.a.string.encode("gbk","ignore")& j4 x. P* }0 r) M7 l0 d- M
print data) Q% e4 _7 q& s9 ^6 J
temp_data.append(data), f, x `- o( ?, x. a
; f2 R" V. v7 x: y9 S3 u
goods = item.find_all("div", style="font-size:12px;") 7 Y2 t+ M. F" v5 s3 L3 u* l 9 Q7 b, i' b7 l n( k$ N# h1 {
#经营产品与联系方式' V( g( b$ A+ A# I8 Y$ K
for i in goods: ! @/ I2 D. s3 L3 w. f8 l, G. m data = i.get_text().encode("gbk","ignore") 3 V2 i. i I' g8 a temp_data.append(data) 3 j% }3 y2 J5 e print data9 m2 U" y7 N9 f/ ^6 ^
#b = item.find_all("b")- t$ u# s) M* _
#print b2 x) `( e8 |0 Q# l8 d5 x5 m; L0 y( F
#链接地址 1 ^& k, ^5 V; Z& N; b pat = re.compile(r'href="([^"]*)"'): ^2 j/ b2 d4 W: R4 O
h = pat.search(str(item)) [; C: M4 c& V) N6 C) @2 J. U: ` if h: : y6 G$ r% _$ k' Y #print h.group(0) 7 Y( I8 r1 o% T( b. x, @' L href = h.group(1)6 ?& z" ^, g% y2 l
print href , ^* g$ t3 r% i, k temp_data.append(h.group(1))5 I! t/ u2 p. r ?8 {' T! ?+ g
# g; {! H( v9 _: V1 t1 C! c
_Num += 1 % A$ _) |( S# e- d #b = item.find_all(text=re.compile("Dormouse"))" r8 Q2 F: @& \7 M: m
#pprint(goods) ; f3 E9 }8 }; S5 w* d; s# y* E #print href) R7 ]+ M9 T1 v: ~( S
#pat = re.compile(r'title="([^"]*)"') 9 |* d# |' N# N9 A& } V #h = pat.search(str(href)) . b. V7 u) K5 Z: \% U #if h:5 E$ E2 T- `* P# m! N
#print h.group(1) ( E5 U$ t+ D7 ]+ k #temp_data.append(h.group(1)) & q7 ]7 T4 V6 k& S+ W' J _DATA.append(temp_data)* j+ Y* \8 V' t' b' @" F7 ^
; u O8 Z3 x- c# F I$ o$ Y
#headers = {'User-Agent':"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1"}##浏览器请求头(大部分网站没有这个请求头会报错、请务必加上哦) . k6 u, e; N$ w9 ^# F- C$ q$ V1 Y#all_url = 'http://www.mzitu.com/all' ##开始的URL地址6 B: a& h. S p& [/ F5 A: \
#start_html = requests.get(all_url, headers=headers) ##使用requests中的get方法来获取all_url(就是:http://www.mzitu.com/all这个地址)的内容 headers为上面设置的请求头、请务必参考requests官方文档解释' V" P8 [- m" w6 B' k" X4 A8 e6 w
#print(start_html.text) ##打印出start_html (请注意,concent是二进制的数据,一般用于下载图片、视频、音频、等多媒体内容是才使用concent, 对于打印网页内容请使用text)- j/ Y) r1 z3 ]- o
: b! ~; ^% o, s5 g2 d) t ]8 j Tdef main() : 3 k- s3 H: R% B global SHARE_Q ! U/ _6 f: A( [4 j threads = [] " Z9 a/ Q# j( E. @, E. g1 l start = time.clock() 5 O2 e* k0 A/ B: t. m0 R% f% u; }$ [ douban_url = "http://company.yktworld.com/comapny_search.asp?page={page}" ) t( G% [! a+ E1 ]; l #向队列中放入任务, 真正使用时, 应该设置为可持续的放入任务- I% j4 i$ o1 a% X
for index in xrange(20) : ( K8 r2 [3 k6 A( n
SHARE_Q.put(douban_url.format(page = index * 1)) 3 t1 O3 c7 a. b9 m* `, v for i in xrange(_WORKER_THREAD_NUM) : 5 w. B6 W+ }; H3 {0 A thread = MyThread(worker,i)) z9 i% b+ G8 j# Z
thread.start() #线程开始处理任务 , F% B0 \' ~* L6 Q- Z( [ 7 c X7 Z2 A; f" M3 I( \ threads.append(thread)3 t% Q3 l# {+ _/ y5 m) y
for thread in threads :/ x! F$ E7 ?. l+ P- a5 O
thread.join()# s* F# ^" n- v( g L- Q1 z
SHARE_Q.join(): R. B" A. Z7 n
i = 0 ' y3 C i2 A! x$ M. F5 S with open("down.txt", "w+") as my_file : z6 ?4 `6 M4 Y% y for page in _DATA : 6 u5 P9 l' U- F- u" N i += 1 ) K/ |1 g" R* d" N( W- G for name in page: ' S: C2 b! _9 ]7 K8 Q my_file.write(name + "\n")9 d7 ~" A) P2 Z1 m! D6 o
3 X0 o: y1 X/ Y0 T& A0 ~ r print "Spider Successful!!!" % U. F$ ]( w# Y4 {: j, U( A/ }% o end = time.clock()4 L% ]7 K! I E0 |; E" m* y
print u'抓取完成!' ( m& A- {1 i8 q! ~+ z print u'总页数:',i 2 ?/ N ~3 L5 @2 c4 ?1 f0 R print u'总条数:',_Num ) L7 p; P; g/ r/ c5 t. N print u'一共用时:',end-start,u'秒' 9 F3 u. `% }' S+ F( _) I% D* A7 [9 H5 t" _' a0 E/ j m4 B
if __name__ == '__main__':, r5 G1 a w# U# T+ _
main() : r( j$ S" O9 _; |3 p0 Q2 r" F1 x# e) P1 W: b8 `