Scrapy使用和入門
1.創建一個scrapy項目
scrapy startproject myspider
創建了一個名爲myspider
的項目,生成了這麼些東西
2.生成一個爬蟲
cd myspider
# 進入項目文件夾裏scrapy genspider itcast itcast.cn
首先進入哪個爬蟲項目(可能有多個),然後生成了一個爬蟲,爬蟲名爲itcast
,爬取的域名範圍是itcast.cn
,怕的就是這爬蟲爬的太快,爬到別的網站去了,所以限制一下
生成了這麼一個文件
這個文件主要就是處理響應信息,提取數據,我們可以寫如下程序,是請求某一個url,提取裏面某些數據
# -*- coding: utf-8 -*-
import scrapy
class ItcastSpider(scrapy.Spider):
name = 'itcast'
allowed_domains = ['itcast.cn']
start_urls = ['http://www.itcast.cn/channel/teacher.shtml#ajavaee']
def parse(self, response):
# 處理start_url地址對應的響應
ret = response.xpath("//div[@class='tea_con']//h3/text()")
print(ret)
然後我們啓動這個爬蟲 scrapy crawl itcast
注意要在項目文件夾下運行,後面一個是爬蟲的名字
看看結果,除了我們需要打印的東西,還要好多亂七八糟的東西,這些其實是日誌
打印這麼多日誌,看起來非常麻煩,我們可以設置一下,在settings.py
中添加一行語句
LOG_LEVEL = "WARNING"
現在運行的時候,除了打印我們想要的信息,只會顯示WARNING及等級以上的信息,比如WARNING和WRONG
我們從上面打印中,還發現,這是一個對象,我們可以提取裏面的數據,使用.extract()
方法
def parse(self, response):
# 處理start_url地址對應的響應
ret = response.xpath("//div[@class='tea_con']//h3/text()").extract()
print(ret)
我們還可以像以前一樣進行分組寫
def parse(self, response):
# 處理start_url地址對應的響應
# ret = response.xpath("//div[@class='tea_con']//h3/text()").extract()
# print(ret)
# 分組
li_list = response.xpath("//div[@class='tea_con']//li")
for li in li_list:
item = {}
item["name"] = li.xpath(".//h3/text()").extract()[0]
item["title"] = li.xpath(".//h4/text()").extract()[0]
print(item)
如果但是這樣寫,有時會出現錯誤,比如某一個字段裏面沒有值,因爲去了第0
個,所以會報錯
其實還有更好的方法,也不用判斷它的長度是否大於0
,它提供了.extract_first()
方法
這個方法的好處在於,當不存在某個字段的時候,會自動填充None
class ItcastSpider(scrapy.Spider):
name = 'itcast'
allowed_domains = ['itcast.cn']
start_urls = ['http://www.itcast.cn/channel/teacher.shtml#ajavaee']
def parse(self, response):
# 處理start_url地址對應的響應
# ret = response.xpath("//div[@class='tea_con']//h3/text()").extract()
# print(ret)
# 分組
li_list = response.xpath("//div[@class='tea_con']//li")
for li in li_list:
item = {}
item["name"] = li.xpath(".//h3/text()").extract_first()
item["title"] = li.xpath(".//h4/text()").extract_first()
print(item)
接下來,我們看看如果將獲取的數據放進pipline
裏面,pipline
主要實現保存數據
使用yield
可以將數據傳到pipline
裏面,(可以返回一個字典,但是不能返回列表)
def parse(self, response):
# 處理start_url地址對應的響應
# ret = response.xpath("//div[@class='tea_con']//h3/text()").extract()
# print(ret)
# 分組
li_list = response.xpath("//div[@class='tea_con']//li")
for li in li_list:
item = {}
item["name"] = li.xpath(".//h3/text()").extract_first()
item["title"] = li.xpath(".//h4/text()").extract_first()
# print(item)
yield item
當然,scrapy
模式是關閉pipline
的,我們需要將它開啓
在settings.py
中,我們需要作如下操作,將這些部分取消註釋就好了
圖中的300
是權重,值越小先執行,因爲可以存在多個pipline
,
在piplines.py
中,我們可以打印數據
class MyspiderPipeline(object):
def process_item(self, item, spider):
print(item)
return item
pipline介紹
當存在多個爬蟲,pipline怎麼能確定這數據是來自與哪一個爬蟲的呢?
pipline裏面的函數還有一個參數,當爬蟲傳遞數據過來,會指名是哪個爬蟲傳過來的
class MyspiderPipeline(object):
def process_item(self, item, spider):
if spider.name == 'itcast':
print(item)
return item
logging模塊的使用
它可以幫助生成日誌
# -*- coding: utf-8 -*-
import scrapy
import logging
logger = logging.getLogger(__name__)
class ItcastSpider(scrapy.Spider):
name = 'itcast'
allowed_domains = ['itcast.cn']
start_urls = ['http://itcast.cn/']
def parse(self, response):
for i in range(10):
item = {}
item["com_from"] = "itcast"
logger.warning(item)
導入模塊,生成實例,調用,打印如下,可以看出哪個文件打印出來的日誌
還可以將日誌保存到本地
在settings.py
裏添加如下語句
LOG_FILE = './log.log' # 文件路徑
這時候,日誌都保存到這個文件裏面,而終端不會顯示
構造request請求
我們如何請求下一頁呢?或者又是別的url?
# -*- coding: utf-8 -*-
import scrapy
class ItcastSpider(scrapy.Spider):
name = 'itcast'
allowed_domains = ['itcast.cn']
start_urls = ['http://itcast.cn/']
def parse(self, response):
'''
do something
'''
# 通過一系列操作獲取到url
next_url = "http://www.xxx.com"
yield scrapy.Request(
next_url,
callback=self.parse
)
還可以帶其他的參數
cookie和headers是分開的
callback可以指向另一個parse函數,不一定是本身
還可以實現參數的傳遞
# -*- coding: utf-8 -*-
import scrapy
class ItcastSpider(scrapy.Spider):
name = 'itcast'
allowed_domains = ['itcast.cn']
start_urls = ['http://itcast.cn/']
def parse(self, response):
'''
do something
'''
item = {}
item["title"] = "xxx"
item["href"] = "xxx"
yield item
# 通過一系列操作獲取到url
next_url = "http://www.xxx.com"
yield scrapy.Request(
next_url,
callback=self.parse1,
meta = {"item":item }
)
def parse1(self, response):
response.meta["item"] # 獲取上面的item
小練習,爬取騰訊的某網站
# -*- coding: utf-8 -*-
import scrapy
class HrSpider(scrapy.Spider):
name = 'hr'
allowed_domains = ['tencent.com']
start_urls = ['http://hr.tencent.com/position.php']
def parse(self, response):
tr_list = response.xpath("//table[@class='tablelist']/tr")[1:-1]
for tr in tr_list:
item = {}
item["title"] = tr.xpath("./td[1]/a/text()").extract_first()
item["position"] = tr.xpath("./td[2]/text()").extract_first()
item["publish_date"] = tr.xpath("./td[5]/a/text()").extract_first()
yield item
# 找到下一頁的url
next_url= response.xpath("//a[@id='next'/@href]").extract_first()
if next_url != "javascript":
yield scrapy.Request(
next_url,
callback=self.parse # 下一頁處理方式一樣,所以返給自己
# 如果處理方式不一樣,可以另外寫一個回調函數
)
設置User-Agent
在setting.py
文件裏,註銷這麼條語句,換取自己的User-Agent