1. 程式人生 > >人民日報語料庫抓取python實現(二)--多執行緒

人民日報語料庫抓取python實現(二)--多執行緒

由於有大量的IO,多執行緒可以提高爬取的效率。出於不同佇列儲存不同url和對於爬蟲進行分工的初衷,這裡實現了兩個佇列shareMonthQueue和shareReportQueue。其中shareMonthQueue儲存所有月份初始url和包含的其他頁面(一個月份有很多page,例:1946年5月包含30個page)。shareReportQueue儲存所有新聞的url。兩個佇列有其專用的爬蟲monthSpider和reportSpider。師兄說:從作業系統的角度來看,兩個佇列是多此一舉,增加程式碼複雜度,並不提高效率。我想了想,師兄說的對。委屈委屈

上程式碼:

#coding:utf-8
#author:zhangyang
#date:2015-5-21
#此程式用於爬取人民日報下的資料資源。主頁面需要提取包括1946年到2003年之間所有月份
#次級頁面是各個月份的所有報道
#末級頁面是報道內容
#使用多執行緒提高爬取效率

import urllib2,bs4,os,re
from time import clock
import threading,Queue

#關於bs4解析url的方法可以參看:http://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html


starturl="http://rmrbw.info/"
shareMonthQueue=Queue.Queue()  #儲存月份url的公共佇列
shareReportQueue=Queue.Queue() #c儲存新聞url的公共佇列
_WORK_MONTH_THREAD_NUM=3       #用於處理月份url的爬蟲數量
_WORK_REPORT_THREAD_NUM_=10    #用於處理新聞url的爬蟲數量
totalNum=0  #全域性計數器
mutex=threading.Lock() #互斥鎖
tlist=[]<span style="white-space:pre">	</span>#執行緒列表
t1=clock()
t2=clock()
t3=clock()
t4=clock()


class monthSplider(threading.Thread):
	def __init__(self,name,dicPath = os.getcwd()+os.path.sep+"data"+os.path.sep):
		threading.Thread.__init__(self)
		self.name=name
		self.dicPath=dicPath
		self.TIMEOUT=10

	def run(self):
		start=clock()
		end=clock()
		while True:
			if shareMonthQueue.empty()==False:
				start=clock()
				monthurl=shareMonthQueue.get()
				try:
					page=urllib2.urlopen(monthurl).read()
					soup=bs4.BeautifulSoup(''.join(page),'lxml')
				except Exception as e:
					print "loading url error at line 43"
					print e
					continue
				title=soup.find('a','fl')   #找到年月的標籤位置
				month=title.contents[0]
				curpath=os.getcwd()
				#print month.encode('utf8')
				datapath=self.dicPath+month.encode('gbk')
				if os.path.exists(datapath)==False:
					os.mkdir(datapath)                       #建立好當月資料夾

				pages=soup.find('div','pages').contents[-1]
				totalpage=pages.split(' ')[3].split('/')[1]   #得到總頁面數
				templist=monthurl.split('=')
				curpage=templist[-1]
				curpage=int(curpage.strip())              #得到當前頁面值
		
				#判斷如果curpage小於totalpage,則把curpage+1得到下一個頁面放入shareMonthQueue中
				if curpage<totalpage:
					templist[-1]=str(curpage+1)
					nexturl='='.join(templist)
					shareMonthQueue.put(nexturl)
				#獲取當前頁面所有新聞的url,並把url放入shareReportQueue裡
				res=soup.find_all(id=re.compile("a_ajax_"))
				for item in res:
					shareReportQueue.put(starturl+item['href'])
			else:
				#在shareMonthQueue為空的情況下等待TIMEOUT秒後退出
				end=clock()
				if (end-start)>self.TIMEOUT:
					break
					
class reportSpider(threading.Thread):
	def __init__(self,name,dicPath = os.getcwd()+os.path.sep+"data"+os.path.sep):
		threading.Thread.__init__(self)
		self.name=name
		self.dicPath=dicPath
		self.TIMEOUT=10
		
	def run(self):
		start=clock()
		end=clock()
		while True:
			if shareReportQueue.empty()==False:
				start=clock()
				url=shareReportQueue.get()
				try:
					page=urllib2.urlopen(url).read()
					soup=bs4.BeautifulSoup(''.join(page),'lxml')
				except Exception as e:
					print "loading url error at line 93"
					print e
					continue
				month=soup.find('a',href=re.compile('thread.php')).get_text().strip() #解析當前網頁所在年月
				month=month.encode('gbk')
				title=soup.find('h1','fl').get_text() #解析當前網頁的新聞標題

				title=title.strip().split(' ')[0]
				#print title.encode('utf8')
				cont_div=soup.find('div','tpc_content')
				cont=cont_div.get_text().strip()   #解析當前網頁的新聞內容
				title=title.encode('gbk')
				cont=cont.encode('gbk')
				try:
					filename=self.dicPath+month+os.path.sep+title+'.txt'
					f=open(filename,'w')
					f.write(cont)
				except Exception as e:
					print str(e)+self.name
					continue
				global totalNum
				global mutex
				if mutex.acquire(1):
					totalNum+=1
					mutex.release()
				#print self.name+"處理了一個頁面"
				if totalNum%100==0:
					global t3,t4
					t4=clock()
					print "已處理了"+str(totalNum)+"條資料,用時"+str(t4-t3)+'s'
			else:
				end=clock()
				if (end-start)>self.TIMEOUT:
					break


def main():
	global t1,t2,t3,t4
	t1=clock()
	pape=urllib2.urlopen(starturl)
	mainsoup=bs4.BeautifulSoup(''.join(pape),'lxml')
	alist=mainsoup.find_all('a',class_='fnamecolor',limit=10)

	for item in alist:
		monthurl=item['href']+'&page=1'
		shareMonthQueue.put(starturl+monthurl)
	t2=clock()
	print "主頁面爬取完成,用時"+str(t2-t1)+'s'

	for i in xrange(_WORK_REPORT_THREAD_NUM_):
		if i<_WORK_MONTH_THREAD_NUM:
			ms=monthSplider('ms'+str(i))
			tlist.append(ms)
		rs=reportSpider('rs'+str(i))
		tlist.append(rs)
	t3=clock()
	print "爬蟲準備就緒,用時"+str(t3-t2)+'s'
	for t in tlist:
		t.start()
	for t in tlist:
		t.join()




if __name__=="__main__":
	main()


相關推薦

人民日報語料python實現--執行

由於有大量的IO,多執行緒可以提高爬取的效率。出於不同佇列儲存不同url和對於爬蟲進行分工的初衷,這裡實現了兩個佇列shareMonthQueue和shareReportQueue。其中shareMonthQueue儲存所有月份初始url和包含的其他頁面(一個月份有很多pa

Java併發程式設計執行四種實現方式

Java實現多執行緒的方式 Java實現多執行緒的方式有4種: 繼承Thread方法、實現Runnable介面、實現Callable介面並通過FutureTask建立執行緒、使用ExecutorService。 其中,前兩種執行緒執行結果沒有返回值,後兩種是有返回值的。 1、繼承Th

一行 Python 實現並行化 -- 日常執行操作的新思路

春節坐在回家的火車上百無聊賴,偶然看到 Parallelism in one line 這篇在 Hacker News 和 reddit 上都評論過百的文章,順手譯出,enjoy:-) http://www.zhangzhibo.net/2014/02/01/

學習大資料第五天:最小乘法的Python實現

1.numpy.random.normal numpy.random.normal numpy.random.normal(loc=0.0, scale=1.0, size=None) Draw random samples from a normal (Gaussi

Python高階程式設計執行

Python 多執行緒 多執行緒類似於同時執行多個不同程式,多執行緒執行有如下優點: 使用執行緒可以把佔據長時間的程式中的任務放到後臺去處理。 使用者介面可以更加吸引人,這樣比如使用者點選了一個按鈕去觸發某些事件的處理,可以彈出一個進度條來顯示處理的進度 程式的執

Java Socket應用執行實現客戶端的通訊

伺服器執行緒處理類ServerThread.java : package com.yijia; import java.io.*; import java.net.Socket; /** * 建立時間:2018/10/4 14:59 * 作者: * 郵箱:[ema

python高階——協程3圖片下載器

import urllib.request import gevent from gevent import monkey monkey.patch_all() def downloader(img_name, img_url): req = urllib.request.urlope

python高階——協程2

協程 協程,又稱微執行緒,纖程。英文名Coroutine。 協程是啥 協程是python箇中另外一種實現多工的方式,只不過比執行緒更小佔用更小執行單元(理解為需要的資源)。 為啥說它是一個執行單元,因為它自帶CPU上下文。這樣只要在合適的時機, 我們可以把一個協程 切換到另一個協程。 只

python高階——協程1迭代器、生成器

迭代器 迭代是訪問集合元素的一種方式。迭代器是一個可以記住遍歷的位置的物件。迭代器物件從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會後退。 1. 可迭代物件 我們已經知道可以對list、tuple、str等型別的資料使用for...in...的迴

python高階——程序2資料夾拷貝器

import os import multiprocessing def copy_file(q, file_name, old_folder_name, new_folder_name): """完成檔案複製""" old_f = open(old_folder_name +

python高階——程序1

程序以及狀態 1. 程序 程式:例如xxx.py這是程式,是一個靜態的 程序:一個程式執行起來後,程式碼+用到的資源 稱之為程序,它是作業系統分配資源的基本單元。 不僅可以通過執行緒完成多工,程序也是可以的 2. 程序的狀態 工作中,任務數往往大於cpu的核數,即一定有一些任

python高階——執行2執行UDP聊天器

import socket import threading def recv_msg(udp_socket): # 接收資料 while True: recv_data = udp_socket.recvfrom(1024) print(recv

python高階——執行1

                                          &nb

作業系統Linux執行--互斥量實現同步

在訊號量中用sem_t結構表示,在互斥量中用pthread_mutexattr_t表示。 使用互斥變數以前,必須首先對它進行初始化,可以把它設定為常量PTHREAD_MUTEX_INITIALIZER(只適合用於靜態分配的互斥量), 也可以用pthread_mutexa

群聊實現tcp和執行

服務端程式碼 package com.cyj.tcp.chat2; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import ja

爬蟲記錄4——執行圖片並下載

還是繼續前幾篇文章的程式碼。 當我們需要爬取的圖片量級比較大的時候,就需要多執行緒爬取下載了。這裡我們用到forkjoin pool來處理併發。 1、DownloadTask下載任務類 package com.dyw.crawler.util;

python進階9執行

# 什麼是執行緒? 執行緒也叫`輕量級程序`,是作業系統能夠進行`運算排程`的`最小`單位,它被包涵在程序之中,是程序中的實際運作單位。執行緒自己不擁有`系統資源`,只擁有一點兒在執行中必不可少的資源,但它可與同屬一個程序的其他執行緒共享程序所擁有的全部資源。一個執行緒可以建立和撤銷另一個執行緒,同一個程序中

1998年人民日報語料,詞的最長,最短匹配 提取問題,

由於語料中包括 [中央/n 人民/n 廣播/vn 電臺/n]nt 此類詞問題,可以選擇最長詞提取,也可以選擇最短詞提取 # -*- coding: utf-8 -*- import codecs wordfile=codecs.open("199801.txt

基於Java的網路爬蟲實現網路小說

package novel.spider.impl; import java.util.ArrayList; import java.util.List; import org.apache.http.client.methods.CloseableHttpResponse; import org.apa

八大排序算法python實現

n) 順序 tails detail 時間 tail 哨兵 插入元素 lang 一、概述 排序有內部排序和外部排序,內部排序是數據記錄在內存中進行排序,而外部排序是因排序的數據很大,一次不能容納全部的排序記錄,在排序過程中需要訪問外存。