開始前的準備工作:
MySQL下載:點我
python MySQL驅動下載:pymysql(pyMySql,直接用pip方式安裝)
全部安裝好之后,我們來熟悉一下pymysql模塊
import pymysql
#創建鏈接對象
connection = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='1234', db='python')
#創建游標 游標用來進行查詢,修改等操作
cursor = connection.cursor()
#定義sql語句 這里的sql語法根據使用的數據庫不同會有一些小差別
sql = "SELECT * FROM python.text_info where text_title='test'"
#執行sql語句 返回受到影響的行數
cursor.execute(sql)
#獲取sql語句執行后的返回數據 默認返回的數據類型為元組
#獲取所有返回
r = cursor.fetchall()
#獲取一個返回
r = cursor.fetchone()
#獲取至多三個返回 不足三個時返回所有
r = cursor.fetchmany(3)
#其他的fetch方法可自行百度
#將返回數據類型改為字典
cursor = connection.cursor(cursor=pymysql.cursors.DictCursor)
#或者在創建連接對象時指定返回數據類型為字典 建議把返回類型修改為字典類型
connection = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='1234', db='python', cursorclass=pymysql.cursors.DictCursor)
#保存所做的修改 在連接關閉之前,如果你沒有調用下面的語句
#那么,你之前的所有修改將不會被保存
connection.commit()
#關閉游標
cursor.close()
#關閉連接
connection.close()
一、確定items
我們要爬取的網站是:http://m.50zw.la
要爬取的是小說的信息,如圖:
所以items.py文件如下:
import scrapy
class TextInfoItem(scrapy.Item):
# name = scrapy.Field()
text_name = scrapy.Field()
text_author = scrapy.Field()
text_type = scrapy.Field()
text_status = scrapy.Field()
text_latest = scrapy.Field()
text_intro = scrapy.Field()
最后信息是要儲存到數據庫里的,所以我們還得創建一個數據庫表。
- 第一步:在開始菜單里找到MySQL Workbench,雙擊打開。MySQL Workbench是MySQL自帶的一個可視化管理工具
- 第二步:在 MySQL Workbench里連接數據庫,并創建一個數據庫 python,然后再在剛剛創建的數據庫里創建一個表 text_info
- 第三步:在 text_info表里逐一添加 text_name,text_author 等屬性,類型全部設置為 varchar,大小除了 text_intro是 1000外,其他的全部設置為 50
MySQL的使用就不詳細講了。如果遇到問題,歡迎評論留言。
二、爬取信息
為了簡單,我們只爬取 50zw網站下的玄幻分類的小說信息。
細節前面已經講過了,這里不再多講,有不懂的可以去看前面的幾篇文章。
廢話不多說,直接上代碼:
import scrapy
from text_info.items import TextInfoItem
class A50zwSpider(scrapy.Spider):
name = '50zw'
allowed_domains = ['m.50zw.la']
start_urls = ['http://m.50zw.la/wapsort/1_1.html']
#主站鏈接 用來拼接
base_site = 'http://m.50zw.la'
def parse(self, response):
book_urls = response.xpath('//table[@class="list-item"]//a/@href').extract()
for book_url in book_urls:
url = self.base_site + book_url
yield scrapy.Request(url, callback=self.getInfo)
#獲取下一頁
next_page_url = self.base_site + response.xpath('//table[@class="page-book"]//a[contains(text(),"下一頁")]/@href').extract()[0]
yield scrapy.Request(next_page_url, callback=self.parse)
def getInfo(self, response):
item = TextInfoItem()
#提取信息
item['text_id'] = response.url.split('_')[1].replace('/', '')
item['text_name'] = response.xpath('//table[1]//p/strong/text()').extract()[0]
item['text_author'] = response.xpath('//table[1]//p/a/text()').extract()[0]
item['text_type'] = response.xpath('//table[1]//p/a/text()').extract()[1]
item['text_status'] = response.xpath('//table[1]//p/text()').extract()[2][3:]
item['text_latest'] = response.xpath('//table[1]//p[5]/text()').extract()[0][3:]
item['text_intro'] = response.xpath('//div[@class="intro"]/text()').extract()[0]
yield item
這里我們通過 yield
來發起一個請求,并通過 callback
參數為這個請求添加回調函數,在請求完成之后會將響應作為參數傳遞給回調函數。
scrapy框架會根據 yield
返回的實例類型來執行不同的操作,如果是 scrapy.Request
對象,scrapy框架會去獲得該對象指向的鏈接并在請求完成后調用該對象的回調函數。
如果是 scrapy.Item
對象,scrapy框架會將這個對象傳遞給 pipelines.py做進一步處理。
這里我們有三個地方使用了 yield
,第一個地方是:
for book_url in book_urls:
url = self.base_site + book_url
yield scrapy.Request(url, callback=self.getInfo)
這里我們在循環里不斷提取小說詳細頁面的鏈接,并通過 yield
來發起請求,并且還將函數 getInfo
作為回調函數來從響應中提取所需的數據。
第二個地方是:
#獲取下一頁
next_page_url = self.base_site + response.xpath('//table[@class="page-book"]//a[contains(text(),"下一頁")]/@href').extract()[0]
yield scrapy.Request(next_page_url, callback=self.parse)
這里是在爬取完一頁的信息后,我們在當前頁面獲取到了下一頁的鏈接,然后通過 yield
發起請求,并且將 parse
自己作為回調函數來處理下一頁的響應。
這有點像遞歸,不過遞歸是函數自己調用自己,這里看起來好像是 parse
調用了自己,但實際上 parse
是由 scrapy框架在獲得響應后調用的。
最后一處使用了 yield
的地方在 getInfo
函數里:
def getInfo(self, response):
item = TextInfoItem()
... ...
item['text_intro'] = response.xpath('//div[@class="intro"]/text()').extract()[0]
yield item
這里我們通過 yield
返回的不是 Request
對象,而是一個 TextInfoItem
對象。
scrap有框架獲得這個對象之后,會將這個對象傳遞給 pipelines.py來做進一步處理。
我們將在 pipelines.py里將傳遞過來的 scrapy.Item
對象保存到數據庫里去。
三、將信息插入數據庫
python對數據庫的操作很簡單,我們簡單了解一下步驟:
- 建立數據庫連接
- 創建操作游標
- 寫sql語句
- 執行sql語句
- 如果執行的是查詢語句,則用fetch語句獲取查詢結果
- 如果執行的是插入、刪除等對數據庫造成了影響的sql語句,還需要執行commit保存修改
貼上代碼:
import pymysql
class TextInfoPipeline(object):
def __init__(self):
#建立數據庫連接
self.connection = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='1234', db='python',charset='utf8')
#創建操作游標
self.cursor = self.connection.cursor()
def process_item(self, item, spider):
#定義sql語句
sql = "INSERT INTO `python`.`text_info` (`text_id`, `text_name`, `text_author`, `text_type`, `text_status`, `text_latest`, `text_intro`) VALUES ('"+item['text_id']+"', '"+item['text_name']+"', '"+item['text_author']+"', '"+item['text_type']+"', '"+item['text_status']+"', '"+item['text_latest']+"', '"+item['text_intro']+"');"
#執行sql語句
self.cursor.execute(sql)
#保存修改
self.connection.commit()
return item
def __del__(self):
#關閉操作游標
self.cursor.close()
#關閉數據庫連接
self.connection.close()
寫在最后:
代碼敲好后不要忘記在settings里開啟pipelines
pymsql連接時默認的編碼是latin-1,所以在建立數據庫連接時會增加參數charset來修改編碼,要修改為utf-8的話得用charset=’utf8‘,而不是charset=’utf-8‘
這個網站有些問題,會時不時報404錯誤,所以在爬的過程中會報list index out of range,這是因為得到了錯誤的網頁,xpath找不到對應得路徑返回了空列表。這是正常現象,并不是代碼出問題了(當然,如果頻繁報錯最好是檢查一下代碼)
貼一張成功后的圖片:
最后的最后,覺得我寫的不錯的話記得關注我哦。