伯樂在線爬蟲項目目的及項目準備:python
1.使用scrapy建立項目sql
2.建立爬蟲,bole 域名 jobbole.com數據庫
3.Start_urls = [‘http://blog.jobbole.com/all-posts/’]api
4.爬取全部頁數的文章dom
5.文章列表頁須要數據異步
a) 縮略圖的地址scrapy
b) 詳情url地址ide
6.詳情頁面要提取的數據函數
# 博客標題工具
# 博客建立時間
# 博客url
# 將url通過md5加密生成id
# 縮略圖的地址
# 圖片保存路徑 #這個屬性考慮好在哪賦值
# 點贊數
# 收藏數
# 評論數
# 博客做者
# 博客標籤
7.將圖片下載,保存到imgs文件夾中
8.將爬取的全部數據存儲到數據庫
建立項目咱們在cmd中進行建立,在開始以前咱們要將數據庫表以及其中字段建立好。
spider爬蟲代碼:
# -*- coding: utf-8 -*- import scrapy import re # ..上級目錄 from ..items import BoleItem # .同級目錄 from .tools import get_number,md5 # MVC Model view controler # 下降代碼耦合性 # MVVC # 作url地址的拼接,若是沒有域名纔會進行拼接 import urlparse class BoleSpider(scrapy.Spider): name = 'bole' allowed_domains = ['jobbole.com'] start_urls = ['http://blog.jobbole.com/all-posts/'] def parse(self, response): # 獲取每一頁的文章url和圖片url a_list = response.xpath(".//*[@id='archive']/div/div[1]/a") for a in a_list: # 獲取博客詳情頁面url # 獲取博客圖片的url a_href = a.xpath("@href").extract_first('') img_src = a.xpath("img/@src").extract_first('') yield scrapy.Request( url=a_href, callback=self.parse_detail, meta={"img_src":img_src} ) next_page = response.xpath("//a[@class='next page-numbers']/@href").extract_first('') if next_page: # 發送請求,請求下一頁 yield scrapy.Request( url=next_page ) def parse_detail(self,response): # 博客詳情地址 blog_url = response.url # 圖片url地址 img_src = response.meta["img_src"] # 圖片地址有可能不完整 if img_src: # 1.拼接URL地址 img_src = urlparse.urljoin('http://www.jobbole.com',img_src) else: img_src = '' # 博客標題 title = response.xpath("//div[@class='entry-header']/h1/text()").extract_first('') # 博客發佈時間 blog_date = response.xpath("//p[@class='entry-meta-hide-on-mobile']/text()").extract_first('').strip().replace(u'·','').strip() # 全部的標籤 tags = response.xpath("//p[@class='entry-meta-hide-on-mobile']/a/text()").extract() # join 將列表中全部的字符串拼接,並以,隔開 # split 將字符串根據某個字符進行分割,返回一個列表 tags = ','.join(tags) # 點贊數 like_count = response.xpath("//h10/text()").extract_first('') # 沒有點贊設置爲0 if like_count: like_count = int(like_count) else: like_count = 0 # 評論數 comment_count = response.xpath("//a[@href='#article-comment']/span/text()").extract_first('') comment_count = get_number(comment_count) # 收藏數 bookmark_count = response.xpath("//span[contains(@class,'bookmark-btn')]/text()").extract_first('') bookmark_count = get_number(bookmark_count) # blog_id # img_path # 建立Item對象 item = BoleItem() item['blog_id'] = md5(response.url) item["title"] = title item["blog_url"] = blog_url # 將圖片url放在列表中 item["img_src"] = [img_src] item["blog_date"] = blog_date item["tags"] = tags item["like_count"] = like_count item["comment_count"] = comment_count item["bookmark_count"] = bookmark_count print title,blog_date,blog_url,img_src,like_count,comment_count,bookmark_count,tags yield item
建立工具包tools,優化代碼,工具包tools代碼:設置隨機請求頭,設置middlewares中內容import hashlib # md5加密函數 def md5(str): import hashlib m = hashlib.md5() m.update(str) return m.hexdigest() # 只要之後須要從字符串中匹配數字,就可使用這個函數 import re def get_number(str): # 正則 pattern = re.compile(r'\d+') rs = re.search(pattern, str) if rs: count = int(rs.group()) else: count = 0 return count
代碼以下:# 設置隨機請求頭 from fake_useragent import UserAgent class RandomUAMiddleware(object): def __init__(self,crawler): super(RandomUAMiddleware, self).__init__() self.crawler = crawler self.ua = UserAgent() @classmethod def from_crawler(cls,crawler): return cls(crawler) # 處理請求函數 def process_request(self,request,spider): # 隨機產生請求頭 request.headers.setdefault('User-Agent',self.ua.random)
在item中建立數據模型類
class BoleItem(scrapy.Item): title = scrapy.Field() blog_url = scrapy.Field() img_src = scrapy.Field() blog_date = scrapy.Field() tags = scrapy.Field() like_count = scrapy.Field() comment_count = scrapy.Field() bookmark_count = scrapy.Field() img_path = scrapy.Field() blog_id = scrapy.Field()
寫入數據庫,咱們使用異步寫入,首先在setting文件中本身配置一些項目信息
# 數據庫配置 MYSQL_HOST = '127.0.0.1' MYSQL_PORT = 3306 MYSQL_USER = 'root' MYSQL_PASSWD = '123456' MYSQL_CHARSET = 'utf8' MYSQL_DBNAME = 'jobbole'
而後設置pipelines,其中包含了咱們寫入數據庫的代碼,和下載圖片的代碼
代碼以下:from scrapy.http.request import Request class MyImagePipeline(ImagesPipeline): # 把當前的item處理完成以後,執行這個函數 def item_completed(self, results, item, info): # 首先判斷要下載的圖片是否有完成信息 if results: try: # 檢測有有沒有圖片信息字典 # 先取出列表中的元組,再從元組中取出字典 img_dic = results[0][1] img_path = img_dic["path"] except Exception,e: print '------',e img_path = '沒有圖片路徑' else: img_path = '沒有圖片信息' # 對item的img_path賦值 item["img_path"] = 'imgs/'+img_path # 返回item return item # 當須要處理媒體文件時,會執行該函數 def get_media_requests(self, item, info): # 獲取圖片的url地址 for src in item['img_src']: return Request( url=src, meta={'item':item} ) # return [Request(x) for x in item["img_src"], []] # 指定圖片存放的路徑 def file_path(self, request, response=None, info=None): # 取出item item = request.meta["item"] # 取出圖片url img_name = request.url.split('/')[-1] return img_name # 異步寫入數據庫 from twisted.enterprise import adbapi from MySQLdb import cursors class MysqlTwistedPipeline(object): @classmethod # 這個函數會自動調用 def from_settings(cls,settings): # 準備好鏈接數據庫須要的參數 db_params = dict( # 複製當前行Ctrl + d host = settings["MYSQL_HOST"], port = settings["MYSQL_PORT"], user = settings["MYSQL_USER"], passwd = settings["MYSQL_PASSWD"], charset = settings["MYSQL_CHARSET"], db = settings["MYSQL_DBNAME"], use_unicode = True, # 指定遊標類型 cursorclass=cursors.DictCursor ) # 建立鏈接池 # 1.要鏈接的名稱 2.鏈接須要的參數 db_pool = adbapi.ConnectionPool('MySQLdb',**db_params) # 返回當前類的對象,而且把db_pool賦值給該類的對象 return cls(db_pool) def __init__(self,db_pool): # 賦值 self.db_pool = db_pool # 處理item函數 def process_item(self,item,spider): # 把要處理的事件進行異步處理 # 1.要處理的事件函數 # 2.事件函數須要的參數 query = self.db_pool.runInteraction(self.do_insert,item) # 執行sql出現錯誤信息 query.addErrback(self.handle_error,item,spider) # 錯誤的緣由 def handle_error(self,failure,item,spider): print failure # 處理插入數據庫的操做 # cursor該函數是鏈接數據庫的函數,而且放在異步去執行,cursor執行sql語句 def do_insert(self,cursor,item): # 1.準備sql語句 sql = 'insert into bolejb(title,blog_url,img_src,blog_date,tags,like_count,comment_count,bookmark_count,img_path,blog_id)VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)' # 2.用cursor遊標執行sql cursor.execute(sql, (item["title"], item["blog_url"], item["img_src"][0], item["blog_date"], item["tags"], item["like_count"],item["comment_count"], item["bookmark_count"], item["img_path"],item["blog_id"])) 最後咱們須要設置咱們setting文件中的內容,將咱們重寫的中間件在setting中進一步設置 DOWNLOADER_MIDDLEWARES = { 'BoleSpider.middlewares.RandomUAMiddleware': 1, } ITEM_PIPELINES = { 'BoleSpider.pipelines.MyImagePipeline': 1, 'BoleSpider.pipelines.MysqlTwistedPipeline': 2, } # 根據哪一個屬性下載圖片 IMAGES_URLS_FIELD = 'img_src' IMAGES_STORE = 'imgs' 爲了方便調試,咱們能夠建立一個debug文件 from scrapy.cmdline import execute execute(['scrapy','crawl','bole'])