Scrapy爬取伯乐在线采用两种入库方法

scrapy基本命令

1.建立scrapy项目

scrapy startproject mybole

2.进入项目列表并在项目目录下创建爬虫文件,此处必须加上你要爬取的链接否则会报错

cd mybole
scrapy genspider jobbole jobbole.com

3.在你创建的scrapy列表中找到spiders就是你创建的爬虫文件夹jobbole.py
在这里插入图片描述
4.初始化的爬虫代码scrapy已帮你建立
在这里插入图片描述
5.现在开始进行爬取网页文章内容的提取采用xpath方法进行爬取,爬去的xpath代码可在Chrome应用商城下载xpathhelper,也可以在命令行模式下输入如下代码就可以进入shell界面

scrapy shell “此处填写具体网址”

6.完整的jobbole.py代码如下:

# -*- coding: utf-8 -*-
import scrapy
import  re
from mybole.items import  MyboleItem
from scrapy.http import  Request#回掉函数
from  urllib import  parse#域名拼接
class MyjobboleSpider(scrapy.Spider):
    name = 'myjobbole'
    allowed_domains = ['blog.jobbole.com']
    start_urls = ['http://blog.jobbole.com/all-posts/']

    def parse(self, response):
        # archive > div:nth-child(1) > div.post-thumb > a
        post_nodes=response.css("#archive .floated-thumb .post-thumb a")
        #post_urls=response.css('//div[@id="archive"]/div[@class="post floated-thumb"]/div[@class="post-thumb"]/a/@href').extract()

        for post_node in post_nodes:
            image_url=post_node.css("img::attr(src)").extract_first('')
            post_url=post_node.css("::attr(href)").extract_first('')
            #meta是个字典,意思是每次运行代码吧图片url提取
            yield  Request(url=parse.urljoin(response.url,post_url),meta={"front_image_url":image_url},  callback=self.parse_detial)#运行url对具体文章提取内容循环多次
        #在response.css(".next.page-numbers::attr(href)")中两个class之间加了空格代表父子,不加空格代表是同一个class
        next_urls=response.css(".next.page-numbers::attr(href)").extract_first('')
        if next_urls:
            #scrapy  根据函数名调用函数进行每页的爬取回到这个def parse(self, response):
            yield  Request(url=parse.urljoin(response.url,next_urls),callback=self.parse)#运行url对具体文章提取内容循环多次

细节性知识点:

#strip()去掉提取内容中的回车换行符即“\r\n”,replace(".","")替换.为空
create_date=response.xpath("//p[@class=‘entry-meta-hide-on-mobile’]/text()").extract()[0].strip().replace("·", “”)

tag_list = [tag for tag in tag_list if not tag.strip().endswith(‘评论’)]#过滤掉“评论”
tags = ‘,’.join(tag_list)

join(): 连接字符串数组。将字符串、元组、列表中的元素以指定的字符(分隔符)连接生成一个新的字符串
语法: ‘sep’.join(seq)
参数说明
sep:分隔符。可以为空
seq:要连接的元素序列、字符串、元组、字典
上面的语法即:以sep作为分隔符,将seq所有的元素合并成一个新的字符串
返回值:返回一个以分隔符sep连接各个元素后生成的字符串
7.items.py代码如下:

import scrapy


class MyboleItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title=scrapy.Field()
    create_date = scrapy.Field()
    url = scrapy.Field()
    url_object_id = scrapy.Field()  # 文章 URL 的 MD5 值
    front_image_url = scrapy.Field()
    front_image_path = scrapy.Field()
    praisenums = scrapy.Field()
    favnums = scrapy.Field()
    commentnums = scrapy.Field()
    content= scrapy.Field()
    tags= scrapy.Field()

items.py相当于python基础知识中的字典,但是在爬去信息的时候对数据操作比较多于是便有了item方便进行数据的操作。

8.piplines.py管道文件代码:
看不懂的代码请看注释

import  json
import pymysql
#from  twisted.enterprise import adbapi
from twisted.enterprise import  adbapi
from scrapy.pipelines.images import ImagesPipeline

class MybolePipeline(object):
    def process_item(self, item, spider):
        return item
 #此处利用scrapy自带scrapy.pipelines.images爬取图片并将图片路径 保存
class MyboleImagePipeline(ImagesPipeline):
    def item_completed(self, results, item, info):
        for ok, v in results:
            image_file_path = v['path']
            item['front_image_path'] = image_file_path
        return item




#json文件存储
class JsonWithEncodingPipeline(object):
    def __init__(self):
        self.file = open('article.json', 'a', encoding='utf-8')
    #此处打开文件的方式“a”与“w”一样但是必须要添加encoding='utf-8'将爬取的xpath代码转换问utf-8类型

    def process_item(self, item, spider):
    #先将item对象转化为字典对象才能进行json文件存储, ensure_ascii=False代表不用ascii存储也就是		         #用中文就好了 
        self.file.write(json.dumps(dict(item), ensure_ascii=False) + ',\n')
        return item    

    def close_spider(self):
        self.file.close()






 #一般数据库存储
 #此处代码最容易报错请确保数据库表 中开头么有空格其他注意细节
class MySQLPipeline(object):
    def __init__(self):
        self.conn = pymysql.connect(host="127.0.0.1",user="root",password="root",db="Articles", charset='utf8')
        self.cursor = self.conn.cursor()

    def process_item(self, item, spider):
        insert_sql = '''
                    insert into jobbole_article(title,create_date,url,url_object_id,front_img_url,
                                                front_img_path,praise_nums,comment_nums,fav_nums,tags,content)
                    values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
                '''
        self.cursor.execute(insert_sql, (
            item['title'], item['create_date'], item['url'], item['url_object_id'],
            item['front_img_url'], item['front_img_path'], item['praise_nums'],
            item['comment_nums'], item['fav_nums'], item['tags'], item['content']
        ))
        self.conn.commit()


    def close_spider(self,spider): #TypeError: close_spider() takes 1 positional argument but 2 were given


        self.cursor.close()
        self.conn.close()




#异步存入数据库目的就是爬虫速度太快数据存入数据库代码,此处异步存储加快速度分布存入,防止数
#据太多数据库堵着
class MysqlTwistedPipline(object):
    #builtins.TypeError: __init__() missing 1 required positional argument: 'db_pool'
    #出现如上错误在from_settinngs 前添加@classmethod
    def __init__(self,dbpool):
        self.dbpool=dbpool
    #从settings获得 数据库配置信息
    @classmethod
    #@classmethod优先级高于__init__使dbpool输出便于初始化
    def from_settings(cls,settings):
        # 用一个db_params接收连接数据库的参数
        dbparms=dict(host=settings["MYSQL_HOST"],db=settings["MYSQL_DBNAME"],
                     user=settings["MYSQL_USER"],password=settings["MYSQL_PASSWORD"],
                     charset="utf8",
                    #设置游标类型
                     cursorclass=pymysql.cursors.DictCursor,
                     use_unicode=True,
                     )
        # 创建连接池
        dbpool=adbapi.ConnectionPool('pymysql',**dbparms)
        # 返回一个pipeline对象
        return cls(dbpool)


    def process_item(self,item,spider):
        #把要执行的sql语句放入连接池
        # 使用Twisted将mysql插入变成异步执行
        # runInteraction可以将传入的函数变成异步的
        query=self.dbpool.runInteraction(self.insert_into,item)
        query.addErrback(self.handle_error,item,spider)
        # 如果sql执行发送错误,自动回调addErrBack()函数
        return item
    def insert_into(self,cursor,item):
        # 会从dbpool取出cursor
        # 执行具体的插入
        insert_sql = '''
                            insert into jobbole_article(title,create_date,url,url_object_id,front_img_url,
                                                        front_img_path,praise_nums,comment_nums,fav_nums,tags,content)
                            values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
                        '''
        cursor.execute(insert_sql, (
            item['title'], item['create_date'], item['url'], item['url_object_id'],
            item['front_img_url'], item['front_img_path'], item['praise_nums'],
            item['comment_nums'], item['fav_nums'], item['tags'], item['content']
        ))
        # 拿传进的cursor进行执行,并且自动完成commit操作

    def handle_error(self, failure, item, spider):
        # 处理异步插入的异常
        print(failure)

9.setting文件是对整个爬虫运行哪块不运行哪块的整体控制:
(1)简单来说就是不遵守robots.txt规定,不写着这句话代表你什么都获取不了

Obey robots.txt rules

ROBOTSTXT_OBEY = False

(2)管道文件控制器,数字越小 代表运行优先级越大,简单来说就是谁小先运行谁

ITEM_PIPELINES = {
   #'mybole.pipelines.MybolePipeline': 300,
#'scrapy.pipelines.images.ImagesPipeline':1,

#"mybole.pipelines.JsonWithEncodingPipeline":300,
    #'mybole.pipelines.MyboleImagePipeline':200,
'scrapy.pipelines.images.ImagesPipeline':1
}

import  os
project_dir=os.path.dirname(os.path.abspath(__file__))#获得当前目录的名称向前取获得目录名
IMAGE_URLS_FIELD='front_image_url'#获取url
#请睁开眼你没有加S导致程序错误
# IMAGES_URLS_FIELD = 'front_image_url'
IMAGE_STORE=os.path.join(project_dir,'images')#设置图片路径

(3)获取图片利用的是自带的图片管道进行爬取,需要与管道相联合
(4)在setting 中添加数据库信息你怎样建立数据库内容随你改变

MYSQL_HOST='localhost'
MYSQL_DBNAME="Articles"
MYSQL_USER="root"
MYSQL_PASSWORD="root"

10.setting.py整体起作用代码在这如需修改请自行修改:

#当我们的item被传输到pipeline我们可以将其进行存储到数据库等工作
ITEM_PIPELINES = {

   #'bole.pipelines.BolePipeline': 300,
   #'bole.pipelines.JsonWithEncodingPipeline': 2,
  # 'bole.pipelines.JsonWithEncodingPipeline': 200,
  #  "bole.pipelines.MysqlTwistedPipline":200,
  #  "bole.pipelines.BoleImagePipeline":100,
   'scrapy.pipelines.images.ImagesPipeline':1
}
MYSQL_HOST='localhost'
MYSQL_DBNAME="Articles"
MYSQL_USER="root"
MYSQL_PASSWORD="root"
import os
# 获取项目目录
project_dir = os.path.dirname(os.path.abspath(__file__))
# 指定需要下载的图片字段,这个字段必须是可迭代对象,这里 front_img_url 就是图片字段名
IMAGES_URLS_FIELD = 'front_img_url'
# 指定图片存储路径,这里将项目目录与 images 目录进行拼接,作为图片存储路径
IMAGES_STORE = os.path.join(project_dir, 'images')
MYSQL_HOST='localhost'
MYSQL_DBNAME="Articles"
MYSQL_USER="root"
MYSQL_PASSWORD="root"

猜你喜欢

转载自blog.csdn.net/work_you_will_see/article/details/84667330
今日推荐