資料採集第三次實驗
作業①:
- 要求:指定一個網站,爬取這個網站中的所有的所有圖片,例如中國氣象網
。分別使用單執行緒和多執行緒的方式爬取。(限定爬取圖片數量為學號後4位)
- 輸出資訊:
將下載的Url資訊在控制檯輸出,並將下載的圖片儲存在weather子檔案中,並給出截圖。
(1)爬取中國氣象網網頁內容
單執行緒實驗過程:
1.先通過主url,檢查頁面,獲取到該頁面下存在的所有a[href]連結,全部存下,後續使用
獲取類似的link,確保圖片數量。
(程式碼如下)start_url = "http://www.weather.com.cn" header = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Edg/94.0.992.38"} r = requests.get(start_url, headers=header) r.raise_for_status() r.encoding = r.apparent_encoding data = r.text soup = BeautifulSoup(data, "html.parser") # 解析html a = '<a href="(.*?)" ' linklist = re.findall(re.compile(a), str(soup)) # 正則表示式獲取link
2.定義封裝一個獲取各個url下圖片連結的函式,得到以下程式碼:
def imagelist(link): header = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Edg/94.0.992.38"} r = requests.get(link, headers=header) r.raise_for_status() r.encoding = r.apparent_encoding data = r.text soup = BeautifulSoup(data, "html.parser") images = soup.select("img") p = r'img.*?src="(.*?)"' imagelist = [] str1 = re.findall(p, str(images), re.S) # # print(str1) for i in range(len(str1)): if str1[i] not in imagelist: imagelist.append(str1[i])if str1[i] else "" # print(imagelist) # print(len(imagelist)) return imagelist
3.定義一個下載圖片的函式(如下)
def download(link): global count file = "E:/weather/" + "第" + str(count+1) + "張.jpg" # file指先在指定資料夾裡建立相關的資料夾才能爬取成功 print("第" + str(count+1) + "張爬取成功") count += 1 urllib.request.urlretrieve(url=link, filename=file)
4.執行結果:
多執行緒實驗過程:
1.與單執行緒實驗類似,運用多執行緒加快載入速度。
首先解析html,同樣的獲取多個linkstart_url = "http://www.weather.com.cn" headers= { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Edg/94.0.992.38"} r = requests.get(start_url, headers=headers) r.raise_for_status() r.encoding = r.apparent_encoding data = r.text soup = BeautifulSoup(data, "html.parser") linklist = [] a = '<a href="(.*?)" ' linklist1 = re.findall(re.compile(a), str(soup)) for i in range(len(linklist1)): if i < 20: linklist.append(linklist1[i]) if linklist1[i] != "javascript:void(0);" else "" # print(len(linklist)) # 到此處便獲取了所有的link threads=[] for i in linklist: imageSpider(i) # 將link呼叫回imageSpider函式
2.獲取單個頁面內的所有img連結
soup=BeautifulSoup(data,"html.parser") images=soup.select("img") for image in images: try: src=image["src"] url=urllib.request.urljoin(start_url,src)
這裡獲取到的圖片連結是img下的src,但是由於網站原因當中混入了http://www.weather.com.cn此網站,因此這裡做下判斷:
if url not in urls: if not str(url).endswith('.cn'):
3.最後封裝download函式,用於多執行緒爬取:這裡先對每個圖片url進行處理,獲取每個圖片連結的後四位,即圖片的格式:最後寫入檔案
def download(url,count): try: if(url[len(url)-4]=="."): type=url[len(url)-4:] else: type="" req=urllib.request.Request(url,headers=headers) data=urllib.request.urlopen(req,timeout=100) data=data.read() fobj=open("E:\images\\"+str(count)+type,"wb") fobj.write(data) fobj.close() print("downloaded "+str(count)+type+"\n") except Exception as err: print(err)
4.多執行緒設定:
T=threading.Thread(target=download,args=(url,count)) T.setDaemon(False) T.start() threads.append(T)
for t in threads: t.join() print("The End")
5.執行結果:
心得體會:
通過本次實驗首先複習了從網站上下載圖片的基本操作,以及如何使用多執行緒來加快下載速度。本次實驗不同的地方在於不在同一個單一頁面內爬取圖片,先要通過主url,找到他的所有分支,在對限定數量的圖片進行下載。總體完成情況較好,也較熟練地掌握了。
作業②:
- 要求:使用scrapy框架復現作業①。 輸出資訊: 同作業①
- 要求:爬取豆瓣電影資料使用scrapy和xpath,並將內容儲存到資料庫,同時將圖片儲存在imgs路徑下。 輸出資訊:
我的Gitee(2)利用scrapy框架下載網站圖片
實驗過程:
1.首先建立scrapy專案2.編寫myspiders,建立myspiders類,定義爬蟲名稱以及start_urls
class myspides(scrapy.Spider): # 設定基礎引數 name = 'myspiders' start_urls = ["http://www.weather.com.cn"]
2.同作業1,定義一個獲取圖片連結的函式
def image(self,link): header = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Edg/94.0.992.38"} r = requests.get(link, headers=header) r.raise_for_status() r.encoding = r.apparent_encoding data = r.text soup = bs4.BeautifulSoup(data, "html.parser") images = soup.select("img") p = r'.+?src="(\S+)"' imagelist = [] str1 = re.findall(p, str(images), re.S) # # print(str1) for i in range(len(str1)): if str1[i] not in imagelist: imagelist.append(str1[i]) if str1[i] else "" # print(imagelist) # print(len(imagelist)) return imagelist
3.在parse函式中同樣的獲取a[href]
a = soup.select("a[href]") links = [] for link in a: links.append(link["href"]) if link["href"] != 'javascript:void(0)' else ""
4.之後便進行圖片的下載:
for i in images: item["images"]= i item["name"] = "E:/weather/" + str(count+1) + ".jpg" urllib.request.urlretrieve(item["images"], filename=item["name"]) count += 1 if count <=112: break yield item
5.在item.py中,定義myspiders中運用到的item項,這裡定義item["images"],item["name"]
6.在setting.py檔案中進行設定:
(注意這裡要忽略網站爬蟲協議)ROBOTSTXT_OBEY = False
在對其他設定:
執行結果
心得體會
該實驗的主要爬蟲思路,和作業①一致,主要是要求用scrapy框架進行實驗,估計老師是為了讓我們熟練使用scrapy框架,經過這次實驗也確實很熟練了,詳細原因見實驗三。
作業③:
我的Gitee序號 電影名稱 導演 演員 簡介 電影評分 電影封面 1 肖申克的救贖 弗蘭克·德拉邦特 蒂姆·羅賓 希望讓人自由 9.7 ./imgs/xsk.jpg 2.... (3)爬取豆瓣相關資訊
實驗過程:
1.先對豆瓣網頁進行觀察,可以發現需要爬取的資訊都分佈在頁面之中:但是這裡發現了一個問題對於要爬取的演員名單,在該頁面下並不完整,導演名稱較為混亂,為了完善該爬蟲,這裡決定在外部介面爬取該部分連結,進入該link,對演員資訊進行爬取。
2.分析完網頁接著就用scrapy框架,對該網站進行爬取。首先建立scrapy專案。
3.編寫主函式myspiders,建立myspides(scrapy.Spider):定義爬蟲名和start_urls
name = 'myspiders' allowed_domains = ['movie.douban.com'] start_urls = ['https://movie.douban.com/top250?start=0']
4.封裝parse(self, response)函式,解析html,利用xpath對資料進行查詢
title = li.xpath("./div[@class='pic']/a/img/@alt").extract_first() img = li.xpath("./div[@class='pic']/a/img/@src").extract_first() score = li.xpath("./div[@class='info']/div[@class='bd']/div[@class='star']/span[position()=2]/text()").extract_first() rank = li.xpath("./div[@class='pic']/em/text()").extract_first() comment = li.xpath("./div[@class='info']/div[@class='bd']/p[position()=2]/span/text()").extract_first()
5.對圖片的下載處理:
file = "E:/movie/" + str(item["title"]) + ".jpg" # file指先在指定資料夾裡建立相關的資料夾才能爬取成功 urllib.request.urlretrieve(item["img"], filename=file) item["file"] = file.strip()
6.繼續利用xpath爬取該電影欄目的連結,進入該連結爬取導演,演員名稱
link = li.xpath("./div[@class='pic']/a/@href").extract_first() soup = bs4.BeautifulSoup(r.text, "html.parser") title = soup.select("div[id='info']") reg = r'<a href=".*?" rel=".*?">(.*?)</a>' actor = re.findall(reg,str(title)) # print(actor[0]) act = soup.select("span[class='actor'] span[class='attrs']")[0].text # print(act) item["actor"] = actor[0] if actor else "" item["star"] = act if act else "" yield item
7.最後對myspiders.py進行翻頁處理:
page = selector.xpath( "//div[@class='paginator']/span[@class='thispage']/following-sibling::a[1]/@href").extract_first() print(page) link_nextpage = "https://movie.douban.com/top250" + str(page) if page: url = response.urljoin(link_nextpage) yield scrapy.Request(url=url, callback=self.parse, dont_filter=True)
8.接著對item.py檔案進行處理,定義所需的items類
class DemoItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() title = scrapy.Field() img = scrapy.Field() link = scrapy.Field() score = scrapy.Field() comment = scrapy.Field() rank = scrapy.Field() actor = scrapy.Field() star = scrapy.Field() file = scrapy.Field() pass
9.對settings要進行處理,一開始我只設定了'demo.pipelines.DemoPipeline': 300,發現無論怎麼爬取都沒有內容,苦苦尋找原因最後發現因為沒有忽略網站爬蟲協議,所以做了如下修改:
ROBOTSTXT_OBEY = False USER_AGENT = 'demo (+http://www.yourdomain.com)'
10.對pipelines進行編寫,這裡主要是做輸出處理和存入資料庫,這裡建立資料庫表
if flag: self.con = sqlite3.connect("movie.db") self.cursor = self.con.cursor() try: self.cursor.execute( "create table movie (int Mrank ,Mtitle varchar(256),Mactor varchar(256),Mstar text,Mcomment varchar(256),Mscore varchar(256),Mfile varchar(256),constraint pk_movie primary key (Mrank,Mtitle))") flag = False except: self.cursor.execute("delete from movie")
插入資料
self.cursor.execute("insert into movie (Mrank,Mtitle,Mactor,Mstar,Mcomment,Mscore,Mfile) values (?,?,?,?,?,?,?)", (item["rank"], item["title"],item["actor"],item["star"], item["comment"], item["score"], item["file"]))
這裡第一次插入資料到資料庫時,驚訝的發現數據少了幾條,最後發現原來設定Mstar varchar(256)
爬取到的部分資料太長導致無法插入,最後設定為Mstar text,解決了該問題。執行結果
可以看見演員名單以及全部爬取下來了。
心得體會
在完成這項作業的過程中面臨了多次網站異常,無法進入的問題,可能是爬取次數太多,
以後一定先快取頁面的html,在進行多次測試,在這次爬蟲第一次接觸了較為複雜的邏輯再次進入一個頁面爬,感覺以後學了selenium,對於這類問題的處理應該沒有這麼麻煩。其次就是對scrapy越來越熟練,感覺爬蟲還是一項需要經常練習的技術,這次也使用了mysql和sqlite兩種資料庫對資料進行儲存,感覺大同小異,最後感謝吳玲老師在實踐課的指導,不然卡在某些debug部分就出不來了。。。
我的Gitee(單)
我的Gitee(多)