摘要:概述在前面兩篇爬蟲學習之基于的網(wǎng)絡(luò)爬蟲和爬蟲學習之簡單的網(wǎng)絡(luò)爬蟲文章中我們通過兩個實際的案例,采用不同的方式進行了內(nèi)容提取。
概述
在前面兩篇(爬蟲學習之基于Scrapy的網(wǎng)絡(luò)爬蟲和爬蟲學習之簡單的網(wǎng)絡(luò)爬蟲)文章中我們通過兩個實際的案例,采用不同的方式進行了內(nèi)容提取。我們對網(wǎng)絡(luò)爬蟲有了一個比較初級的認識,只要發(fā)起請求獲取響應的網(wǎng)頁內(nèi)容,然后對內(nèi)容進行格式化存儲。很多時候我們抓取到的內(nèi)容可能會發(fā)生重復,也有可能是需要計算或者組織過的全新的內(nèi)容甚至是需要登錄后才能訪問的內(nèi)容, 那么這一篇我們來學習一下Scrapy的Item部分以及了解如何使用Scrapy來進行自動登錄。
起步首先我們使用Scrapy的命令行創(chuàng)建一個新的項目
scrapy startproject douban
運行后,我們就有了下面這樣的目錄結(jié)構(gòu)
+ douban # 根目錄 |- douban # Python的項目目錄 |- spiders # 爬蟲Spider部分,用于提取網(wǎng)頁內(nèi)容 |- __init__.py |- __init__.py |- items.py # 爬蟲item, 用于定義數(shù)據(jù)結(jié)構(gòu) |- pipelines.py # 爬蟲pipeline,用于處理提取的結(jié)構(gòu),比如清洗數(shù)據(jù)、去重等 |- settings.py # Scrapy框架參數(shù)項目參數(shù)設(shè)置 |- scrapy.cfg # 爬蟲部署相關(guān)設(shè)置
Scrapy為我們生成了已經(jīng)組織好的目錄結(jié)構(gòu),上面的注釋部分解釋了每個文件及目錄的作用。
建立目標本篇我們來建立兩個目標,這兩個目標都是基于豆瓣網(wǎng):
目標一:抓取豆瓣TOP250的圖書信息并保存成csv文件
目標二:抓取我的第一頁豆郵標題(需要登錄),并保存成csv文件
分析目標一目標一是豆瓣的TOP250圖書信息,首先我們進入到TOP250的列表(https://book.douban.com/top250) ,我用圖示圈出我們這次要爬取的內(nèi)容,具體請看圖示:
從圖上的框線中我們主要圈出了書名、價格、出版年份、出版社、評分,其中出版年份,出版社以及價格是在一行中,這個我們需要進一步處理。
分頁的處理:總記錄是250條,每頁是25條圖書信息,共分了10頁。
實現(xiàn)目標一需要用到的概念:
Item
Item Pipeline
首先建立Scrapy的Item, Scrapy的Item就是我們需要存儲的數(shù)據(jù)結(jié)構(gòu),先修改items, 然后在spiders目錄中新建一個名為bookspider.py的Python文件,由于我們需要在一堆字符串中提取出出版社和價格等信息所以我們這里需要對抓取的內(nèi)容進一步處理, 在這之前還需要修改settings.py文件:
加入faker的模擬USER_AGENT數(shù)據(jù)防止被豆瓣屏蔽,
也可以設(shè)置DEFAULT_REQUEST_HEADERS參數(shù)。
修改ITEM_PIPELINES
代碼如下所示:
items.py
# -*- coding: utf-8 -*- """by sudo rm -rf http://imchenkun.com""" import scrapy class DoubanBookItem(scrapy.Item): name = scrapy.Field() # 書名 price = scrapy.Field() # 價格 edition_year = scrapy.Field() # 出版年份 publisher = scrapy.Field() # 出版社 ratings = scrapy.Field() # 評分
bookspider.py
# -*- coding:utf-8 -*- """by sudo rm -rf http://imchenkun.com""" import scrapy from douban.items import DoubanBookItem class BookSpider(scrapy.Spider): name = "douban-book" allowed_domains = ["douban.com"] start_urls = [ "https://book.douban.com/top250" ] def parse(self, response): # 請求第一頁 yield scrapy.Request(response.url, callback=self.parse_next) # 請求其它頁 for page in response.xpath("http://div[@class="paginator"]/a"): link = page.xpath("@href").extract()[0] yield scrapy.Request(link, callback=self.parse_next) def parse_next(self, response): for item in response.xpath("http://tr[@class="item"]"): book = DoubanBookItem() book["name"] = item.xpath("td[2]/div[1]/a/@title").extract()[0] book["price"] = item.xpath("td[2]/p/text()").extract()[0] book["ratings"] = item.xpath("td[2]/div[2]/span[2]/text()").extract()[0] yield book
pipelines.py
# -*- coding: utf-8 -*- """by sudo rm -rf http://imchenkun.com""" class DoubanBookPipeline(object): def process_item(self, item, spider): info = item["price"].split(" / ") # [法] 圣埃克蘇佩里 / 馬振聘 / 人民文學出版社 / 2003-8 / 22.00元 item["name"] = item["name"] item["price"] = info[-1] item["edition_year"] = info[-2] item["publisher"] = info[-3] return item
最后我們到douban的根目錄中執(zhí)行以下命令來運行爬蟲來執(zhí)行并導出數(shù)據(jù)到csv文件
scrapy crawl douban-book -o douban_book_top250.csv
csv文件截圖如下:
分析目標二目標二是建立在理解了目標一的基礎(chǔ)上進行的,因為豆瓣登錄次數(shù)過多會有驗證碼出現(xiàn),這里提供一種手工填寫驗證碼的方式,暫時不討論如何去識別驗證碼,目標二的核心概念是如何提交POST表單和登錄成功后帶Cookie的請求。首先我們可以看到頁面結(jié)構(gòu)如下圖所示:
實現(xiàn)目標二定義Item
# -*- coding: utf-8 -*-import scrapy """by sudo rm -rf http://imchenkun.com""" class DoubanMailItem(scrapy.Item): sender_time = scrapy.Field() # 發(fā)送時間 sender_from = scrapy.Field() # 發(fā)送人 url = scrapy.Field() # 豆郵詳細地址 title = scrapy.Field() # 豆郵標題
定義doumailspider
# -*- coding:utf-8 -*- """by sudo rm -rf http://imchenkun.com""" import scrapy from faker import Factory from douban.items import DoubanMailItem import urlparse f = Factory.create() class MailSpider(scrapy.Spider): name = "douban-mail" allowed_domains = ["accounts.douban.com", "douban.com"] start_urls = [ "https://www.douban.com/" ] headers = { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3", "Connection": "keep-alive", "Host": "accounts.douban.com", "User-Agent": f.user_agent() } formdata = { "form_email": "您的賬號", "form_password": "您的密碼", # "captcha-solution": "", # "captcha-id": "", "login": "登錄", "redir": "https://www.douban.com/", "source": "None" } def start_requests(self): return [scrapy.Request(url="https://www.douban.com/accounts/login", headers=self.headers, meta={"cookiejar": 1}, callback=self.parse_login)] def parse_login(self, response): # 如果有驗證碼要人為處理 if "captcha_image" in response.body: print "Copy the link:" link = response.xpath("http://img[@class="captcha_image"]/@src").extract()[0] print link captcha_solution = raw_input("captcha-solution:") captcha_id = urlparse.parse_qs(urlparse.urlparse(link).query, True)["id"] self.formdata["captcha-solution"] = captcha_solution self.formdata["captcha-id"] = captcha_id return [scrapy.FormRequest.from_response(response, formdata=self.formdata, headers=self.headers, meta={"cookiejar": response.meta["cookiejar"]}, callback=self.after_login )] def after_login(self, response): print response.status self.headers["Host"] = "www.douban.com" return scrapy.Request(url="https://www.douban.com/doumail/", meta={"cookiejar": response.meta["cookiejar"]}, headers=self.headers, callback=self.parse_mail) def parse_mail(self, response): print response.status for item in response.xpath("http://div[@class="doumail-list"]/ul/li"): mail = DoubanMailItem() mail["sender_time"] = item.xpath("div[2]/div/span[1]/text()").extract()[0] mail["sender_from"] = item.xpath("div[2]/div/span[2]/text()").extract()[0] mail["url"] = item.xpath("div[2]/p/a/@href").extract()[0] mail["title"] = item.xpath("div[2]/p/a/text()").extract()[0] print mail yield mail
這里需要注意的有三個地方:
第一個是meta中的cookiejar
Scrapy 通過使用 cookiejar Request meta key來支持單spider追蹤多cookie session。默認情況下其使用一個cookie jar(session),不過您可以傳遞一個標示符來使用多個。
start_requests 我們這里重寫了爬蟲爬取得第一個頁面,這里一開始就進去到登錄頁面
當執(zhí)行爬蟲的時候,我們需要把打印出來的驗證碼地址粘貼到瀏覽器中,手動輸入到控制上完成驗證。
同目標一一樣需要設(shè)置settings中的相關(guān)參數(shù),唯一不同的是ITEM_PIPELINES。
最后我們使用以下命令來啟動爬蟲
scrapy crawl douban-mail -o douban_mail_page1.csv
csv文件截圖如下:
Github地址:https://github.com/imchenkun/ick-spider/tree/master/douban
總結(jié)本篇我們學習了如果定義Item以及如何對Item進行進一步處理(Item Pipeline), 還通過登錄豆瓣的案例來了解了如果使用Scrapy進行表單提交和Cookie追蹤,也了解了對于有驗證碼的情況該如何處理,當然我們這里暫時還不討論如何識別驗證碼。關(guān)于Scrapy的更高級的一些用法和特性可以進一步閱讀Scrapy官網(wǎng)的文檔。
特別申明:本文所提到的豆瓣網(wǎng)只是拿來進行爬蟲的技術(shù)交流學習,讀者涉及到的所有侵權(quán)問題都與本人無關(guān),也希望大家在學習實戰(zhàn)的過程中不要大量的爬取內(nèi)容對服務(wù)器造成負擔
本文首發(fā)在sudo rm -rf 采用署名(BY)-非商業(yè)性使用(NC)-禁止演繹(ND) 轉(zhuǎn)載請注明原作者
--EOF--
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/38070.html
摘要:不過不用擔心,中有很多非常優(yōu)秀的爬蟲框架,比如我們接下來要學習到的。結(jié)合以上分析我們基本確定了本次爬蟲的各個路線入口,接下來我們就開始通過程序來實現(xiàn)本次的目標。這里我們的目的是建立一種寫爬蟲的思路,而不在于怎么使用工具來爬數(shù)據(jù)。 概述 在上一篇文章《爬蟲學習之一個簡單的網(wǎng)絡(luò)爬蟲》中我們對爬蟲的概念有了一個初步的認識,并且通過Python的一些第三方庫很方便的提取了我們想要的內(nèi)容,但是...
摘要:時間永遠都過得那么快,一晃從年注冊,到現(xiàn)在已經(jīng)過去了年那些被我藏在收藏夾吃灰的文章,已經(jīng)太多了,是時候把他們整理一下了。那是因為收藏夾太亂,橡皮擦給設(shè)置私密了,不收拾不好看呀。 ...
摘要:楚江數(shù)據(jù)是專業(yè)的互聯(lián)網(wǎng)數(shù)據(jù)技術(shù)服務(wù),現(xiàn)整理出零基礎(chǔ)如何學爬蟲技術(shù)以供學習,。本文來源知乎作者路人甲鏈接楚江數(shù)據(jù)提供網(wǎng)站數(shù)據(jù)采集和爬蟲軟件定制開發(fā)服務(wù),服務(wù)范圍涵蓋社交網(wǎng)絡(luò)電子商務(wù)分類信息學術(shù)研究等。 楚江數(shù)據(jù)是專業(yè)的互聯(lián)網(wǎng)數(shù)據(jù)技術(shù)服務(wù),現(xiàn)整理出零基礎(chǔ)如何學爬蟲技術(shù)以供學習,http://www.chujiangdata.com。 第一:Python爬蟲學習系列教程(來源于某博主:htt...
摘要:最近這兩周在忙著給公司爬一點數(shù)據(jù),更文的速度有一點下降,預計今天就爬完了,總結(jié)總結(jié)經(jīng)驗。一個爬蟲的框架?;镜葍r于選擇其中的文字提取屬性文檔,這個我不會,我也沒看使用這個類庫解析如請求方式可以用來給中文字符數(shù)據(jù)放入傳遞即可。 最近這兩周在忙著給公司爬一點數(shù)據(jù),更文的速度有一點下降,預計今天就爬完了,總結(jié)總結(jié)經(jīng)驗。 其實之前我司是有專門做爬蟲的,不用前端這邊出人干活。后來那人離職了,有可...
摘要:最近這兩周在忙著給公司爬一點數(shù)據(jù),更文的速度有一點下降,預計今天就爬完了,總結(jié)總結(jié)經(jīng)驗。一個爬蟲的框架。基本等價于選擇其中的文字提取屬性文檔,這個我不會,我也沒看使用這個類庫解析如請求方式可以用來給中文字符數(shù)據(jù)放入傳遞即可。 最近這兩周在忙著給公司爬一點數(shù)據(jù),更文的速度有一點下降,預計今天就爬完了,總結(jié)總結(jié)經(jīng)驗。 其實之前我司是有專門做爬蟲的,不用前端這邊出人干活。后來那人離職了,有可...
閱讀 1845·2021-09-22 15:23
閱讀 3278·2021-09-04 16:45
閱讀 1901·2021-07-29 14:49
閱讀 2779·2019-08-30 15:44
閱讀 1529·2019-08-29 16:36
閱讀 1048·2019-08-29 11:03
閱讀 1520·2019-08-26 13:53
閱讀 516·2019-08-26 11:57