一文搞定Scrapy和Selenium整合使用
前言
scrapy和selenium的整合使用
先定個小目標實現(xiàn)萬物皆可爬!我們是用scrapy框架來快速爬取頁面上的數(shù)據(jù),它是自帶并發(fā)的,速度是可以的。但是一些ajax異步的請求我們不能這么爬取。我們要視同selenium來進行l(wèi)azy loading,也就是懶加載,渲染到頁面加載數(shù)據(jù)。
一、開始準備
1. 包管理和安裝chrome驅動
首先你要安裝以下包:
pip install scrapy pip install selenium == 3.0.0 pip install pymysql pip install bs4
selenium新版本有bug,用3.0的版本。
chrome驅動的exe執(zhí)行文件,放到你項目的根目錄即可。下載地址:驅動
2. 爬蟲項目的創(chuàng)建(舉個栗子)
創(chuàng)建項目
scrapy startproject cnki
您爬取的目標網(wǎng)站
scrapy genspider cnki https://www.cnki.net
運行爬蟲
# 運行不導出(一般在pipelines做導出操作) scrapy crawl cnki # 針對不同的選擇可以導出為xlsx、json等格式文件 scrapy crawl demo -o demo.csv
3. setting.py的配置
配置數(shù)據(jù)源,如下:
DB_HOST = 'localhost' DB_PORT = 3306 DB_USER = 'root' DB_PASSWORD ='123456' DB_DATABASE = 'spider'
防止打印log日志信息
LOG_LEVEL = 'WARNING'
配置USER_AGENT(瀏覽器控制臺找一個)
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36
配置DEFAULT_REQUEST_HEADERS(瀏覽器控制臺找一個)
{ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en', }
隨機延遲
DOWNLOAD_DELAY = 3 RANDOMIZE_DOWNLOAD_DELAY=True
中間件權重配置(這些中間件給他打開 并且按照項目實際需求配置權重,越小越先執(zhí)行)
SPIDER_MIDDLEWARES # 蜘蛛中間件 DOWNLOADER_MIDDLEWARES # 下載中間件 ITEM_PIPELINES # 管道
二、代碼演示
1. 主爬蟲程序
1.初始化selenium (如果您不需要selenium,可以忽略這個 )
def __init__(self, *args,**kwargs): option = webdriver.ChromeOptions() # 實例化一個瀏覽器對象 option.add_argument('--headless') # 添加參數(shù),option可以是headless,--headless,-headless self.driver = webdriver.Chrome(options=option) # 創(chuàng)建一個無頭瀏覽器 # self.driver = webdriver.Chrome() # 創(chuàng)建一個無頭瀏覽器 time.sleep(3) super(CnkiSpider, self).__init__(*args, **kwargs) dispatcher.connect(self.close_driver,signals.spider_closed)
2.定義開始請求頁面
下面我只放了一個url,其實可以定義一組的然后進行遍歷(一般是分頁url使用)
還有cookie、代理也可以在這里配置,詳情請看進去看源碼(不過一般在中間件配置)
def start_requests(self): for url in self.start_urls: yield scrapy.Request( # 這里可以設置多個頁面,一般用于分頁的 url=url, )
3.關閉selenium(一定要關掉)
def close_driver(self): print("爬蟲正在退出,執(zhí)行關閉瀏覽器哦") time.sleep(2) self.driver.quit()
4.解析頁面
這里就不多說,八仙過海各顯神通
def parse(self,response: HtmlResponse): sel = Selector(response) dds = sel.css('.journal > .main-w1 > dl > dd') for dd in dds: title = dd.css('h6 > a::attr(title)').extract_first() link = dd.css('h6 > a::attr(href)').extract_first() link = response.urljoin(link) author = dd.css('.baseinfo > span > #author::attr(title)').extract_first() abstract = dd.css('.abstract::text').extract_first() count = dd.css('.opts > .opts-count > li > em::text').extract_first() count = int(count) date = dd.css('.opts > .opts-count > .date::text').extract_first() date = date.split(':')[1] date = datetime.datetime.strptime(date,"%Y-%m-%d") rc = Recommend() rc['title'] = title rc['link'] = link rc['author'] = author rc['abstract'] = abstract rc['count'] = count rc['date'] = date yield rc
這里要注意我們yield可以返回不僅是item,也可以是Request,進行頁面詳情的請求(套娃)
yield Request( url=link, # 這是上面頁面上的鏈接,用來進一步請求 callback=self.parse_detail, # 這是回調函數(shù) cb_kwargs={'item':rc} # 這是把上面的item傳遞下來 )
2. 中間件的配置
1.針對selenium
沒有selenium請忽略
class SeleniumDownloaderMiddleware: def process_request(self, request , spider): if spider.name == 'cnki': spider.driver.get(request.url) time.sleep(2) print(f"當前訪問{request.url}") spider.driver.refresh() time.sleep(3) return HtmlResponse(url=spider.driver.current_url,body=spider.driver.page_source,encoding='utf-8')
2.SpiderMiddleware保持默認配置即可
3.DownloaderMiddleware可以配置cookie和代理之類的。如:
# 我自定義的解析cookie方法 def get_cookie_dict(): cookie_str = 填上你的cookie cookie_dict = {} for item in cookie_str.split(';'): key, value = item.split('=',maxsplit=1) cookie_dict[key] = value return cookie_dict COOKIES_DICT = get_cookie_dict()
# 這是DownloaderMiddleware這是自帶的方法哈 def process_request(self, request : Request, spider): request.cookies = COOKIES_DICT return None
3. 定義item對象
用來接受爬蟲到的數(shù)據(jù)
class Recommend(scrapy.Item): title = scrapy.Field() author = scrapy.Field() abstract = scrapy.Field() link = scrapy.Field() count = scrapy.Field() date = scrapy.Field()
4. 定義管道
實現(xiàn)對數(shù)據(jù)庫的導入(你也可以寫excel的)
class RecommendPipeline: @classmethod def from_crawler(cls, crawler: Crawler): host = crawler.settings['DB_HOST'] port = crawler.settings['DB_PORT'] username = crawler.settings['DB_USER'] password = crawler.settings['DB_PASSWORD'] database = crawler.settings['DB_DATABASE'] return cls(host, port, username, password, database) def __init__(self, host, port, username, password, database): # 1、與數(shù)據(jù)庫建立連接 self.conn = pymysql.connect(host=host, port=port, user=username, password=password, database=database, charset='utf8mb4') # 2、創(chuàng)建游標 self.cursor = self.conn.cursor() # 3、批處理需要的容器 self.data = [] def process_item(self, item, spider): title = item.get('title', '') author = item.get('author', '') abstract = item.get('abstract', '') link = item.get('link', '') count = item.get('count', '') date = item.get('date', '') # 如果要實現(xiàn)批處理: self.data.append((title,author,abstract,link,count,date)) # 如果存夠了10條就進數(shù)據(jù)庫 if len(self.data) == 10: self._to_write_db() # 然后再清空 self.data.clear() return item def close_spider(self, spider): # 如果最后不滿足10條 if len(self.data) > 0: self._to_write_db() self.conn.close() def _to_write_db(self): # 作為一個實時的推薦,我希望將查到的數(shù)據(jù)作為一個temp # 'delete from tb_recommend where 1 = 1' 刪除滿,并且主鍵自增不會從1開始 self.cursor.execute( 'truncate table tb_recommend' ) self.cursor.executemany( 'insert into tb_recommend (title,author,abstract,link,count,date) values (%s, %s, %s, %s, %s, %s)', self.data ) self.conn.commit()
記得寫入setting.py,設置其權重。
*接下來您就可以按照這種方法‘愉’ ‘快’的進行爬蟲啦!??! *
總結
這是scrapy和selenium的具體整合使用,scrapy框架的內容還有很多方法還沒用到,都有待開發(fā)。其次就是selenium的填充之類的操作還沒有使用,還需要去復習selenium的api。
相關文章
Python3之亂碼\xe6\x97\xa0\xe6\xb3\x95處理方式
這篇文章主要介紹了Python3之亂碼\xe6\x97\xa0\xe6\xb3\x95處理方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-05-05python之線程池map()方法傳遞多參數(shù)list
這篇文章主要介紹了python之線程池map()方法傳遞多參數(shù)list問題,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03