1. 程式人生 > >Python requests爬蟲例項

Python requests爬蟲例項

作業系統:Windows
Python:3.5
歡迎加入學習交流QQ群:657341423

需要用到的庫:
requests
wxPython
docx
win32api需要安裝pywin32

解釋:
requests這個用來做爬蟲,基本上不用多作解釋
wxPython和win32api主要生成軟體的操作介面,給使用者使用。
docx主要將爬取的結果,用word顯示出來。

網頁分析:
這裡以南方日報每天的報紙為例:請點選
這裡寫圖片描述
可以看到,url後面是一個日期和node為尾的,日期就代表當天的報紙,node是報紙的首頁,看到下面紅色標記的是每篇新聞的標題,點開標題看到
這裡寫圖片描述
點開標題後,看到新的url,日期和一個content為尾的。content是代表每篇新聞的詳細報道。下面紅色標記的是我們需要的正文。
當然,有時候會附帶一些圖片的,而且是會有多張圖片。如:
這裡寫圖片描述

設計思路:
以http://epaper.southcn.com/nfdaily/html/2017-06/21/node_581.htm 開始。
然後獲取這個html裡面的帶有content的url連結。
再通過獲取的url組合成每篇新聞報道的url,然後獲取這些url的正文內容,標題和圖片。

分析node網頁的標題url
這裡寫圖片描述
可以發現,每個標題都是這樣的格式。

再分析content網頁的正文和標題,圖片。
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

總的來說,就是在node這個網頁,獲取每篇新聞詳細資訊的url,而且這些url帶有content的,然後迴圈訪問這些url,獲取每篇新聞的標題,正文和圖片即可實現。

實現程式碼:

#爬蟲庫
from bs4 import BeautifulSoup
import requests
import queue
import re
#讀寫word
from docx import Document
from docx.shared import Inches
from io import StringIO
#介面設計
import os
import wx
import win32api
import win32con
import win32gui

		
def mkdir(path):#判斷是否有資料夾,沒則新建
    path=path.strip()
    path=path.rstrip("\\")
    isExists=os.path.exists(path)
    if not isExists:
        os.makedirs(path)
        return True
    else:
        return False	
PicSavePath=os.getcwd()+"\\news"
mkpath=PicSavePath
mkdir(mkpath)
	
class MyFrame(wx.Frame): 
	def __init__(self, parent, title): 
		super(MyFrame, self).__init__(parent, title = title, size = (500, 350)) 

		self.InitUI()
		self.Centre() 
		self.Show()      

	def InitUI(self): 
		panel = wx.Panel(self)

		hbox = wx.BoxSizer(wx.HORIZONTAL)

		fgs = wx.FlexGridSizer(4, 2, 10,10)

		Sort = wx.StaticText(panel, label = "年   份") 
		sale = wx.StaticText(panel, label = "月   份") 
		keys = wx.StaticText(panel, label = "關鍵字")

		self.tc1 = wx.ComboBox(panel,value="年份",choices=["2016","2017"]) 
		self.tc2 = wx.ComboBox(panel,value="月份",choices=["1","2","3","4","5","6","7","8","9","10","11","12"]) 
		self.tc3 = wx.TextCtrl(panel, style = wx.TE_MULTILINE)

		bt1=wx.Button(panel,label = "查詢")
		bt2=wx.Button(panel,label = "清除")

		fgs.AddMany([(Sort), (self.tc1, 1, wx.EXPAND), (sale),  
		(self.tc2, 1, wx.EXPAND), (keys, 1, wx.EXPAND), (self.tc3, 1, wx.EXPAND),(bt1),(bt2)])  
		fgs.AddGrowableRow(2, 1) 
		fgs.AddGrowableCol(1, 1)  
		hbox.Add(fgs, proportion = 2, flag = wx.ALL|wx.EXPAND, border = 15) 
		panel.SetSizer(hbox) 
		
		bt1.Bind( wx.EVT_BUTTON, self.query )
		bt2.Bind( wx.EVT_BUTTON, self.cleanValue )
		
	def cleanValue(self,event):
		self.tc1.ChangeValue('年份')
		self.tc2.ChangeValue('月份')
		self.tc3.Clear()
	
	def dowloadPic(self,imageUrl,filePath):
		r = requests.get(imageUrl)
		with open(filePath, "wb") as code:
			code.write(r.content)
		

	def query(self,event):
		queryyear=self.tc1.GetValue().strip()
		KeyValue=self.tc3.GetValue().strip()
		
		if KeyValue:
			Keylist=KeyValue.split('\n')
		else:
			Keylist=['南海區專利代理人培訓','專利管理師','南海區專利代理行業自律公約','南海區專利特派員','智慧財產權投融資對接會','科技服務業集聚區',
			'專利質押融資','rttp','南海區榮獲中國專利獎','智慧財產權優勢示範企業','智慧財產權日系列活動','南海基地']
		
		if queryyear.isdigit()==False:
			win32api.MessageBox(0,'請選擇年份', '提示',win32con.MB_ICONASTERISK|win32con.MB_OKCANCEL)
		
		else:
			#獲取全年的新聞
			for i in range(12):
				for k in range(31):
					#設定日期的月日格式
					if len(str(i+1))==1:
						month="0"+str(i+1)
					else:
						month=str(i+1)
						
					if len(str(k+1))==1:
						day="0"+str(k+1)
					else:
						day=str(k+1)	
					#生成日期	
					dateDay=queryyear+"-"+month+'/'+day
					print(dateDay)
					self.queryDay(dateDay,Keylist)
			win32api.MessageBox(0,'資料採集完成', '提示',win32con.MB_ICONASTERISK|win32con.MB_OKCANCEL)
			
	def queryDay(self,dateDay,Keylist):
		try:
			urlList=[]
			PicUrl=[]
			#獲取每天的報紙裡面每篇新聞的url
			papgedate=dateDay
			url='http://epaper.southcn.com/nfdaily/html/%s/node_2.htm' %papgedate
			r=requests.get(url)
			soup=BeautifulSoup(r.content.decode("utf-8"),"html.parser")
			temp=soup.find_all('div',id='btdh')[0]
			herfList=temp.find_all('a',href=re.compile("content"))
			for i in herfList:
				StarIndex=re.search('href=',str(i)).span()[1]
				EndIndex=re.search('target',str(i)).span()[0]
				tempValue=str(i)[StarIndex:EndIndex].replace('"','').strip()
				if tempValue:
					urlList.append(tempValue)
			urlList=sorted(set(urlList))
			
			for i in urlList:
				url='http://epaper.southcn.com/nfdaily/html/%s/%s' %(papgedate,i)
				r=requests.get(url)
				#獲取每篇新聞的標題和正文
				soup=BeautifulSoup(r.content.decode('utf-8'),"html.parser")
				title=soup.find_all('div',id='print_area')[0].find_all('h1')[0].getText()
				ContentText=soup.find_all('founder-content')[0].getText()
				PicList=soup.find_all('div',id='print_area')[0].find_all('img',src=re.compile('/res/'))
				
				#關鍵字篩選
				Mycontent=False
				for kw in Keylist:
					if kw in title:
						Mycontent=True
					elif kw in ContentText:
						Mycontent=True
				if Mycontent:
					for j,k in enumerate(PicList):
						StarIndex=re.search('/res',str(k)).span()[0]
						EndIndex=re.search('"/>',str(k)).span()[0]
						tempValue=str(k)[StarIndex:EndIndex].replace('"','').strip()
						imageUrl='http://epaper.southcn.com/nfdaily'+tempValue
						self.dowloadPic(imageUrl,i.replace('.','')+"_"+str(j)+".jpg")
						PicList[j]=i.replace('.','')+"_"+str(j)+".jpg"
					#寫入word
					document = Document()	
					document.add_heading(title, 0)
					document.add_paragraph(ContentText)
					for p in PicList:
						document.add_picture(p, width=Inches(1.25))
						os.remove(p)
					document.save('news//'+title.strip()+'.docx')
		except Exception as e:
			pass
		
app = wx.App() 
MyFrame(None, title = 'XyJw') 
app.MainLoop()	
	
	
	

程式碼設計思路:
1.程式碼執行會生成一個使用者操作介面,使用者可以選擇年份和輸入關鍵字對新聞進行篩選,(這裡的月份還沒做相應的開發。)目前只是做了爬取一年裡面的全部新聞,然後將每篇新聞的標題和正文和關鍵字對比,如果含有關鍵字的,會爬取下來生成word。如果關鍵字不輸入資料,會預設程式裡面的關鍵字進行篩選。
2.在年份設定那裡,我是預設每個月都是31日的,如果當月不存在31日的,在queryDay裡面會跳到Exception不作處理。
這裡寫圖片描述

執行結果:
這裡寫圖片描述
這裡寫圖片描述

這裡是爬取含義廣東為關鍵字的新聞。

擴充套件和優化

  1. 在這裡,我們會發現,網頁的爬取速度很慢。畢竟迴圈的次數比較多。而且很受網速的影響。
  2. 對於上述程式碼,可以做優化,最外的迴圈,是每次生成一個日期,然後再爬取,這裡可以用多執行緒方法,一次爬取2天或者3天的資料,如果是一次2天資料,按一個月32天計算,就是迴圈16次即可。
  3. 關鍵字優化,如果要更加精準地獲取新聞資訊,這裡可以自然語言處理方法。
    這裡介紹一個現有的方法,就是用百度的現有自然語言處理方法:請點選
    當然也可以自己編寫,具體自行百度。