scrapy 基础学习

#scrapy 的优势
1 request和beautifulsoup是库,scrapy是框架,不是一个层次的
2 scrapy框架中可以加入request和beautifulsoup,可以基层很多第三方库
3 scrapy基于twisted,实际上是一个异步i/o的框架,所以性能是最大的优势
4 scrapy方便扩展,提供了很多内置功能
5 scrapy内置的css和xpath selector 非常方便,beautifulsoup最大的缺点就是慢。

#网页分类

1 静态网页
事先在服务器端生成好的
2 动态网页
根据传递的参数不同,发送请求获取浏览器
3 webservice(restapi)

#爬虫能做什么
1 搜索引擎—百度 谷歌 垂直搜索引擎
2 推荐引擎–今日头条 根据浏览记录来爬取相关内容推荐给用户
3 机器学习的数据样本
4 数据分析,舆情分析

#正则表达式
!正则表达式是反向匹配,从后往前
!正则是默认贪婪模式,贪婪模式,就是在整个表达式匹配成功的前提下,尽可能多的匹配
!正则表达式会提取括号内的内容
1 "^" :定义开头字符,以符号后面的字符开头,"^b"代表以b字母开头
"$":定义结尾字符,以符号前面的字符结尾
2 ".": 任意字符,中英文下划线都可以
3 “*”:它前面的字符可以出现多次
4 “?”:非贪婪模式,非贪婪模式,就是在整个表达式匹配成功的前提下,尽可能少的匹配
5 “+” :符号前面的内容至少出现一次,
6 {2} 前面的字符出现的次数
{2,5} 出现最小2次最多5次
{2,}出现2次或者更多
7 “|”:或,要在括号里使用
8“[abcd]”:中括号里面的字符满足一个即可,
可以写区间[0-9] a-z [A-Za-z0-9_]
中括号里面写:^1 表示非1
9 \s 空格
\S 只要不是空格都可以
\w [A-Za-z0-9_]
\W 和\w相反
\d 数字
10 [\u4E00-\u9FA5] 汉字

深度优先和广度优先
深度优先,递归实现,如果递归太深或者递归没有跳出会发生栈溢出
广度优先,队列实现

爬虫去重策略

1 把访问过的url保存到数据库中,但是速度慢
2 把访问过的url保存到set中,也就是内存中,只需要o(1)的代价就可以查询到
url,但是内存占用大
3.url经过md5等方法哈希后保存到set中,可以将字符缩减到固定长度,比如128bit,就是16byte
4.用bitmap方法,将访问过的url通过hash函数映射到某一位,申请一个8个bit,也就是一个byte,将访问过的hash函数映射到某一个位置上
5 bloofilter方法对bitmap进行改进,多重hash函数降低冲突

#xpath 中的css语法
css选择器

选择器

css

用scrapy创建项目
1.解析文章
2.获取列表和下一页,用Request,传url,来调用解析文章的方法
3. item
在item.py中创建一个item实例,然后在jobbole爬取文章后实例化这个item并填充数据,调用yeild 实例 就会把item传到pipelins中
下载图片并保存到本地
创建一个images文件夹
要把setting.py中的

	    ITEM_PIPELINES = {
	    	    'ArticleSprider.pipelines.ArticlespriderPipeline': 300,
	    	}
	
	打开,改成:
	
	    ITEM_PIPELINES = {
	        'ArticleSprider.pipelines.ArticlespriderPipeline': 300,
	        'scrapy.pipelines.images.ImagesPipeline': 1  ,# 后面的数字越小,越优先执行
	    }
	    IMAGES_URLS_FIELD = "front_img_url"  # 这样scrapy会去找到这个front_img_url 然后下载图片
	    project_dir = os.path.abspath(os.path.dirname(__file__))  # 当前目录的路径
	    IMAGES_STORE = os.path.join(project_dir,'images')   # 配置图片保存路径
	记得import os ,配置以后会把front_img_url当成一个数组,所以在填充数据的时候记得以数组填充。这里还需要安装一个东西,在cmd进入虚拟环境`pip install pillow`  用豆瓣云会快一点

获取图片的路径
重写pipelines文件中处理图片的方法,
导入scrapy.pipelines.images包,获取path并填充到item在返回
from scrapy.pipelines.images import ImagesPipeline
class ArticleImagePipeline(ImagesPipeline):
def item_completed(self, results, item, info):
for ok, value in results:
image_file_path = value[“path”]
item[“front_img_path”] = image_file_path
return item
更改settings文件:
ITEM_PIPELINES = {
‘ArticleSprider.pipelines.ArticlespriderPipeline’: 300,
# ‘scrapy.pipelines.images.ImagesPipeline’: 1 ,# 后面的数字越小,越优先执行
‘ArticleSprider.pipelines.ArticleImagePipeline’: 1,
}
把图片的url经过md5计算后的结果
创建一个保存常用方法的目录,utils,在utils下新建一个common文件,在common中编写一个计算MD5的方法,接着在解析文章的方法中导入这个方法,再调用方法填充到item实例
把item写成json文件
在pipelines中,写一个方法打开文件,然后把传过来的item转成dict,再转成json
然后用self.file.write(lines)写入文件中,接着关闭self.file.close()
import codecs # 可以避免很多编码问题
import json
class JsonWithEncodingPipeline(object):
def init(self):
self.file = codecs.open(‘article.json’, ‘w’, encoding=‘utf-8’)
def process_item(self, item, spider):
lines = json.dumps(dict(item), ensure_ascii=False) + ‘\n’
self.file.write(lines)
return item
def spider_closed(self,spider):
self.file.close()
更改setting:
ITEM_PIPELINES = {
‘ArticleSprider.pipelines.JsonWithEncodingPipeline’: 2,
# ‘scrapy.pipelines.images.ImagesPipeline’: 1 ,# 后面的数字越小,越优先执行
‘ArticleSprider.pipelines.ArticleImagePipeline’: 1,
}

4.将item保存到数据库
方法(一)
1 进入虚拟环境,安装 mysqlclient: pip install mysqlclient
2.定义pipelines

class MysqlPipeline(object):
    def __init__(self):  #连接数据库
        self.conn = MySQLdb.connect('host', 'user', 'password', 'dbname', charset='utf8', use_unicode=True)
        self.cursor = self.conn.cursor()

    def process_item(self,item,sprider):  #执行sql
        insert_sql = "insert into jobbole_article(title,url,create_date,fav_nums) VALUES (%s,%s,%s,%s)"
        self.cursor.execute(insert_sql, (item['title'], item['url'], item['create_date'], item['fav_nums']))
        self.conn.commit()

3.在setting中配置pipeline: ‘BlizzaedSpider.pipelines.MysqlPipeline’: 1,

方法(二) 爬取数据多了之后插入速度会跟不上爬取速度,就会发生堵塞,所以考虑第二种方法

1 在setting文件最后加上 配置

MYSQL_HOST = "192.168.0.106"
MYSQL_DBNAMQ = "jobbole_article"
MYSQL_USER = "root"
MYSQL_PASSWORD = "root"

2 创建pipeline


from twisted.enterprise import adbapi

.....

class MysqlTwistedPipeline(object):
    def __init__(self,dbpool):
        self.dbpool = dbpool

    @classmethod
    #  通过这个注解定义这个函数,这个函数实际上就是一个setting,可以来读取setting的
    def from_settings(cls, settings):
        #  这个方法的名称是固定的,在初始化的时候就被scrapy调用
        dbparms = dict(
        host = settings["MYSQL_HOST"],
        db = settings["MYSQL_DBNAME"],
        user = settings["MYSQL_USER"],
        password = settings["MYSQL_PASSWORD"],
        charset = 'utf8',
        cursorclass = MySQLdb.cursors.DictCursor,
        use_unicode = True,
        )


        dbpool = adbapi.ConnectionPool("MySQLdb",**dbparms)

        return cls(dbpool)

    def process_item(self,item,spider):
        #  使用twisted将mysql插入变成异步执行
        query = self.dbpool.runInteraction(self.do_insert, item)
        query.addErrback(self.handle_error, item, spider) #处理异常

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

    def do_insert(self, cursor, item):
        #执行具体的插入
        insert_sql = "insert into jobbole_article(title,url,create_date,fav_nums) VALUES (%s,%s,%s,%s)"
        self.execute(insert_sql, (item['title'], item['url'], item['create_date'], item['fav_nums']))
        #会自动commit

itemLoder
目的:为了使代码更便于维护,提高可配置性,可以把规则存到数据库,需要的时候再到数据库查询,做一个匹配映射,还可以简省代码
items:

from scrapy.loader import ItemLoader


class NgaItemLoder(ItemLoader):
    default_output_processor = TakeFirst()

def update_time(value):
    if value:
        time = value.replace('上传于', '')
        date = time.strip()
    else:
        date = datetime.datetime.now().date()
    return date


def get_nums(value):
    if value:
        nums = int(value[0])
    else:
        nums = 0
    return nums


class NgaspiderItem(scrapy.Item):
    url = scrapy.Field()
    url_id = scrapy.Field()
    front_img_url = scrapy.Field()
    front_img_url_path = scrapy.Field()
    title = scrapy.Field()
    update_time = scrapy.Field(
        input_processor=MapCompose(update_time)
    )
    author = scrapy.Field()
    playnum = scrapy.Field(

    )
    comment_count = scrapy.Field(
        input_processor=MapCompose(get_nums)
    )
    like_count = scrapy.Field(
        input_processor=MapCompose(get_nums)
    )

使用:

  def parse_details(self, response):
 		duowan = NgaspiderItem()
        itemloder = NgaItemLoder(item = NgaspiderItem(), response = response)
        itemloder.add_value("url", response.url)
        itemloder.add_value("url_id", get_md5(response.url))
        image_url_list = []
        image_url_list.append(response.meta.get('front_img_url', ''))
        itemloder.add_value("front_img_url", [image_url_list])
        itemloder.add_css("title", ".play-title::text")
        itemloder.add_xpath("update_time", '//*[@id="wrap"]/div/div[3]/div[1]/div[3]/div[1]/div[1]/span/text()')
        itemloder.add_xpath('author', '//*[@id="wrap"]/div/div[3]/div[1]/div[3]/div[1]/div[1]/h3/a/text()')
        itemloder.add_css('playnum', '#video_play_num::attr(data-play-num)')
        itemloder.add_xpath('comment_count', '//*[@id="first_comment_count"]/text()')
        itemloder.add_xpath('like_count', '//*[@id="wrap"]/div/div[3]/div[1]/div[3]/div[1]/div[3]/div[2]/a[3]/text()')
        duowan = itemloder.load_item()

        yield duowan


收集所有404url以及404页面数(数据收集器的使用)

 # 收集所有404url以及404页面数
    handle_httpstatus_list = [404]

    def __init__(self):
        self.fail_urls = []


    def parse(self, response):
        if response.status == 404:
            self.fail_urls.append(response.url)
            self.crawler.stats.inc_value('failed_url')
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值