Python安装使用Scrapy框架


Posted in Python onApril 12, 2022

一、架构介绍

Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,使用它可以以快速、简单、可扩展的方式从网站中提取所需的数据。但目前Scrapy的用途十分广泛,可用于如数据挖掘、监测和自动化测试等领域,也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。

Scrapy 是基于twisted框架开发而来,twisted是一个流行的事件驱动的python网络框架。因此Scrapy使用了一种非阻塞(又名异步)的代码来实现并发。整体架构大致如下

IO多路复用

Python安装使用Scrapy框架

# 引擎(EGINE)(大总管)

引擎负责控制系统所有组件之间的数据流,并在某些动作发生时触发事件。有关详细信息,请参见上面的数据流部分。

# 调度器(SCHEDULER)

用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL的优先级队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址

# 下载器(DOWLOADER)

用于下载网页内容, 并将网页内容返回给EGINE,下载器是建立在twisted这个高效的异步模型上的

# 爬虫(SPIDERS)

SPIDERS是开发人员自定义的类,用来解析responses,并且提取items,或者发送新的请求

# 项目管道(ITEM PIPLINES)

在items被提取后负责处理它们,主要包括清理、验证、持久化(比如存到数据库)等操作

# 两个中间件

-爬虫中间件

-下载中间件(用的最多,加头,加代理,加cookie,集成selenium)

二、安装创建和启动

# 1 框架 不是 模块
# 2 号称爬虫界的django(你会发现,跟django很多地方一样)
# 3 安装
	-mac,linux平台:pip3 install scrapy
  -windows平台:pip3 install scrapy(大部分人可以)
  	- 如果失败:
      1、pip3 install wheel #安装后,便支持通过wheel文件安装软件,wheel文件官网:https://www.lfd.uci.edu/~gohlke/pythonlibs
      3、pip3 install lxml
      4、pip3 install pyopenssl
      5、下载并安装pywin32:https://sourceforge.net/projects/pywin32/files/pywin32/
      6、下载twisted的wheel文件:http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
      7、执行pip3 install 下载目录\Twisted-17.9.0-cp36-cp36m-win_amd64.whl
      8、pip3 install scrapy
 # 4 在script文件夹下会有scrapy.exe可执行文件
	-创建scrapy项目:scrapy startproject 项目名   (django创建项目)
  	-创建爬虫:scrapy genspider 爬虫名 要爬取的网站地址   # 可以创建多个爬虫
 # 5 命令启动爬虫
		-scrapy crawl 爬虫名字
  		-scrapy crawl 爬虫名字 --nolog   # 没有日志输出启动
 # 6 文件执行爬虫(推荐使用)
	-在项目路径下创建一个main.py,右键执行即可
  	from scrapy.cmdline import execute
    # execute(['scrapy','crawl','chouti','--nolog'])  # 没有设置日志级别
    execute(['scrapy','crawl','chouti'])			  # 设置了日志级别

三、配置文件目录介绍

-crawl_chouti   # 项目名
  -crawl_chouti # 跟项目一个名,文件夹
    -spiders    # spiders:放着爬虫  genspider生成的爬虫,都放在这下面
    	-__init__.py
      -chouti.py # 抽屉爬虫
      -cnblogs.py # cnblogs 爬虫
    -items.py     # 对比django中的models.py文件 ,写一个个的模型类
    -middlewares.py  # 中间件(爬虫中间件,下载中间件),中间件写在这
    -pipelines.py   # 写持久化的地方(持久化到文件,mysql,redis,mongodb)
    -settings.py    # 配置文件
  -scrapy.cfg       # 不用关注,上线相关的
# 配置文件settings.py
ROBOTSTXT_OBEY = False   # 是否遵循爬虫协议,强行运行
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'    # 请求头中的ua,去浏览器复制,或者用ua池拿
LOG_LEVEL='ERROR' # 这样配置,程序错误信息才会打印,
	#启动爬虫直接 scrapy crawl 爬虫名   就没有日志输出
  	# scrapy crawl 爬虫名 --nolog  # 配置了就不需要这样启动了
# 爬虫文件
class ChoutiSpider(scrapy.Spider):
    name = 'chouti'   # 爬虫名字
    allowed_domains = ['https://dig.chouti.com/']  # 允许爬取的域,想要多爬就注释掉
    start_urls = ['https://dig.chouti.com/']   # 起始爬取的位置,爬虫一启动,会先向它发请求
    def parse(self, response):  # 解析,请求回来,自动执行parser,在这个方法中做解析
        print('---------------------------',response)

Python安装使用Scrapy框架

四、爬取数据,并解析

# 1 解析,可以使用bs4解析
from bs4 import BeautifulSoup
soup=BeautifulSoup(response.text,'lxml')
soup.find_all()  # bs4解析
soup.select()  # css解析
# 2 内置的解析器
response.css  
response.xpath
# 内置解析 
  # 所有用css或者xpath选择出来的都放在列表中
  # 取第一个:extract_first()
  # 取出所有extract()
# css选择器取文本和属性:
    # .link-title::text  # 取文本,数据都在data中
    # .link-title::attr(href)   # 取属性,数据都在data中
# xpath选择器取文本和属性
    # .//a[contains(@class,"link-title")/text()]
    #.//a[contains(@class,"link-title")/@href]
# 内置css选择期,取所有
div_list = response.css('.link-con .link-item')
for div in div_list:
    content = div.css('.link-title').extract()
    print(content)

五、数据持久化

# 方式一(不推荐)
  -1 parser解析函数,return 列表,列表套字典
    # 命令   (支持:('json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle')
    # 数据到aa.json文件中
  -2 scrapy crawl chouti -o aa.json   
# 代码:
lis = []
for div in div_list:
    content = div.select('.link-title')[0].text
    lis.append({'title':content})
    return lis
# 方式二 pipline的方式(管道)
   -1 在items.py中创建模型类
   -2 在爬虫中chouti.py,引入,把解析的数据放到item对象中(要用中括号)
   -3 yield item对象
   -4 配置文件配置管道
       ITEM_PIPELINES = {
        # 数字表示优先级(数字越小,优先级越大)
       'crawl_chouti.pipelines.CrawlChoutiPipeline': 300,
       'crawl_chouti.pipelines.CrawlChoutiRedisPipeline': 301,
    	}
  -5 pipline.py中写持久化的类
        spider_open  # 方法,一开始就打开文件
        process_item # 方法,写入文件
        spider_close # 方法,关闭文件

保存到文件

# choutiaa.py 爬虫文件
import scrapy
from chouti.items import ChoutiItem  # 导入模型类
class ChoutiaaSpider(scrapy.Spider):
    name = 'choutiaa'
    # allowed_domains = ['https://dig.chouti.com/']   # 允许爬取的域
    start_urls = ['https://dig.chouti.com//']   # 起始爬取位置
    # 解析,请求回来,自动执行parse,在这个方法中解析
    def parse(self, response):
        print('----------------',response)
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(response.text,'lxml')
        div_list = soup.select('.link-con .link-item')
        for div in div_list:
            content = div.select('.link-title')[0].text
            href = div.select('.link-title')[0].attrs['href']
            item = ChoutiItem()  # 生成模型对象
            item['content'] = content  # 添加值
            item['href'] = href
            yield item  # 必须用yield  	
# items.py 模型类文件
import scrapy
class ChoutiItem(scrapy.Item):
    content = scrapy.Field()
    href = scrapy.Field()
# pipelines.py 数据持久化文件
class ChoutiPipeline(object):
    def open_spider(self, spider):
        # 一开始就打开文件
        self.f = open('a.txt', 'w', encoding='utf-8')
    def process_item(self, item, spider):
        # print(item)
        # 写入文件的操作
        self.f.write(item['content'])
        self.f.write(item['href'])
        self.f.write('\n')
        return item
    def close_spider(self, spider):
        # 写入完毕,最后关闭文件
        self.f.close()
# setting.py
ITEM_PIPELINES = {
    # 数字表示优先级,越小优先级越高
   'chouti.pipelines.ChoutiPipeline': 300,
   'chouti.pipelines.ChoutiRedisPipeline': 301,
}

保存到redis

# settings.ps
ITEM_PIPELINES = {
    # 数字表示优先级,越小优先级越高
   'chouti.pipelines.ChoutiPipeline': 300,
   'chouti.pipelines.ChoutiRedisPipeline': 301,
}
# pipelines.py
# 保存到redis
from redis import Redis
class ChoutiRedisPipeline(object):
    def open_spider(self, spider):
        # 不写参数就用默认配置
        self.conn = Redis(password='123')  # 一开始就拿到redis对象
    def process_item(self, item, spider):
        print(item)
        import json
        s = json.dumps({'content': item['content'], 'href': item['href']})
        self.conn.hset('choudi_article', item['id'], s)
        return item
    def close_spider(self, spoder):
        pass
        # self.conn.close()
# chouti.py
import scrapy
from chouti.items import ChoutiItem  # 导入模型类
class ChoutiaaSpider(scrapy.Spider):
    name = 'choutiaa'
    # allowed_domains = ['https://dig.chouti.com/']   # 允许爬取的域
    start_urls = ['https://dig.chouti.com//']   # 起始爬取位置
    # 解析,请求回来,自动执行parse,在这个方法中解析
    def parse(self, response):
        print('----------------',response)
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(response.text,'lxml')
        div_list = soup.select('.link-con .link-item')
        for div in div_list:
            content = div.select('.link-title')[0].text
            href = div.select('.link-title')[0].attrs['href']
            id = div.attrs['data-id']
            item = ChoutiItem()  # 生成模型对象
            item['content'] = content  # 添加值
            item['href'] = href
            item['id'] = id
            yield item  # 必须用yield

保存到MongoDB

#一.下载并安装mongodb
pip install pymongo
#二、在settings中打开PIPELINES并把数据库相应配置写入
ITEM_PIPELINES = {
    '<spider_name>.pipelines.ChoutiPipeline': 300,
}
MONGODB_HOST = '127.0.0.1'
# 端口号,默认27017
MONGODB_PORT = 27017
# 设置数据库名称
MONGODB_DBNAME = 'Chouti'
# 存放本数据的表名称
MONGODB_DOCNAME = 'Chouti'
#三.修改pipelines文件
import pymongo
from scrapy.utils.project import get_project_settings
settings = get_project_settings()
class DouluodaluPipeline(object):
    def __init__(self):
        # 获取setting主机名、端口号和数据库名称
        host = settings['MONGODB_HOST']
        port = settings['MONGODB_PORT']
        dbname = settings['MONGODB_DBNAME']
        # 创建数据库连接
        client = pymongo.MongoClient(host=host,port=port)
        # 指向指定数据库
        mdb = client[dbname]
        # 获取数据库里面存放数据的表名
        self.post = mdb[settings['MONGODB_DOCNAME']]
    def process_item(self, item, spider):
        data = dict(item)
        # 向指定的表里添加数据
        self.post.insert(data)
        return item

保存到mysql

import pymysql.cursors
class MySQLPipeline(object):
    def __init__(self):
        # 连接数据库
        self.connect = pymysql.connect(
            host='127.0.0.1',  # 数据库地址
            port=3306,  # 数据库端口
            db='scrapyMysql',  # 数据库名
            user='root',  # 数据库用户名
            passwd='root',  # 数据库密码
            charset='utf8',  # 编码方式
            use_unicode=True)
        # 通过cursor执行增删查改
        self.cursor = self.connect.cursor()
    def process_item(self, item, spider):
        self.cursor.execute(
            """insert into mingyan(tag, cont)
            value (%s, %s)""",  # 纯属python操作mysql知识,不熟悉请恶补
            (item['tag'],  # item里面定义的字段和表字段对应
             item['cont'],))
        # 提交sql语句
        self.connect.commit()
        return item  # 必须实现返回

六、动作链,控制滑动的验证码

from selenium import webdriver
from selenium.webdriver import ActionChains
import time
bro=webdriver.Chrome(executable_path='./chromedriver')
bro.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
bro.implicitly_wait(10)
#切换frame(很少)
bro.switch_to.frame('iframeResult')
div=bro.find_element_by_xpath('//*[@id="draggable"]')
# 1 生成一个动作练对象
action=ActionChains(bro)
# 2 点击并夯住某个控件
action.click_and_hold(div)
# 3 移动(三种方式)
# action.move_by_offset() # 通过坐标(x,y)
# action.move_to_element() # 到另一个标签
# action.move_to_element_with_offset() # 到另一个标签,再偏移一部分
for i in range(5):
    action.move_by_offset(10,10)
# 4 真正的移动
action.perform()

# 5 释放控件(松开鼠标)
action.release()

async def login():
    for res in setting.user:
        try:
            username = res[0]
            password = res[1]
            # headless参数设为False,则变成有头模式
            browser = await launch(
                {'headless': False}
            )
            # 打开一个页面
            page = await browser.newPage()
            await page.setViewport(viewport={'width': 1280, 'height': 800})
            res = await page.goto('https://login.taobao.com/', options={'timeout': 10000})
            await page.type('#fm-login-id', username)
            await page.type('#fm-login-password', password)
            await page.waitFor(1000)  # 等待时间
            slider = await page.querySelector('#nc_1_n1z')  # 是否有滑块
            if slider:
                try:
                    print('有滑块')
                    await page.hover('#nc_1_n1z')  # 不同场景的验证码模块能名字不同。
                    await page.mouse.down()
                    await page.mouse.move(2000, 0, {'delay': random.randint(1000, 2000)})
                    await page.mouse.up()
                except Exception as e:
                    print(e)
                    input('验证失败,人工登录:')
            else:
                print('没有滑块')
            await page.click("#login-form > div.fm-btn > button")  # 点击登录
            input('进入登录成功页面后,按回车:')
            return page
        except Exception as e:
            continue

七、提高爬取效率

- 在配置文件中进行相关的配置即可:(默认还有一套setting)
#1 增加并发:
默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改CONCURRENT_REQUESTS = 100值为100,并发设置成了为100。
#2 提高日志级别:
在运行scrapy时,会有大量日志信息的输出,为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。在配置文件中编写:LOG_LEVEL = ‘INFO'
# 3 禁止cookie:
如果不是真的需要cookie,则在scrapy爬取数据时可以禁止cookie从而减少CPU的使用率,提升爬取效率。在配置文件中编写:COOKIES_ENABLED = False
# 4禁止重试:
对失败的HTTP进行重新请求(重试)会减慢爬取速度,因此可以禁止重试。在配置文件中编写:RETRY_ENABLED = False
# 5 减少下载超时:
如果对一个非常慢的链接进行爬取,减少下载超时可以能让卡住的链接快速被放弃,从而提升效率。在配置文件中进行编写:DOWNLOAD_TIMEOUT = 10 超时时间为10s

八、fake-useragent池

# pip3 install fake-useragent
from fake_useragent import UserAgent
ua = UserAgent(verify_ssl=False)
print(ua.random)  # 随机获取一个UserAgent

九、中间件配置

#大中间件:下载中间件,爬虫中间件
# 1 写在middlewares.py中(名字随便命名)
# 2 配置生效()
# 爬虫中间件
SPIDER_MIDDLEWARES = {
   'cnblogs_crawl.middlewares.CnblogsCrawlSpiderMiddleware': 543,
}
# 下载中间件
DOWNLOADER_MIDDLEWARES = {
   'cnblogs_crawl.middlewares.CnblogsCrawlDownloaderMiddleware': 543,
}
# 下载中间件
# 在cnblogs_crawl.middlewares.CnblogsCrawlDownloaderMiddleware中有五个方法
# 请求出去的时候
def process_request(self, request, spider)
	# Must either:
    # - return None:   # 返回none继续处理,进入下一个中间件
    # - return Response: 当次请求结束,把Response丢给引擎处理(可以自己爬,包装成Response)
    # - return Request : 相当于把Request重新给了引擎,引擎再去做调度
    # - 抛异常:执行process_exception
# 请求回来的时候
def process_response(self, request, response, spider)
	# - return a Response object :继续处理当次Response,继续走后续的中间件
    # - return a Request object:重新给引擎做调度
	# - 抛异常:执行process_exception
# 请求异常的时候
def process_exception(self, request, exception, spider)
	# - return None: 不处理异常,继续丢给下面
    # - return a Response:停止异常处理,不丢给下面。给引擎。Response给爬虫分析数据
    # - return a Request:停止异常处理,不丢给下面。给引擎。Request重新调度

process_exception 错误处理

class CnblogsSpider(scrapy.Spider):
    name = 'cnblogs4'
    allowed_domains = ['www.cnblogs.com']
    start_urls = ['http://wwwsadasd.cnblogs.com/']   # 错误的网址,报错走异常处理
# 走异常处理,重新返回一个正确的Request对象
def process_exception(self, request, exception, spider):
    print(request.url)  # http://wwwsadasd.cnblogs.com/
    from scrapy.http import Request
    return Request('http://www.cnblogs.com/',callback=spider.parser_detail)

process_request 加代理,加cookie等

def process_request(self, request, spider):
        # 1 加cookie(request.cookies就是访问该网站的cookie)
        print(request.cookies)
        request.cookies={'name':"jeff",'age':18}  # 从你的cookie池中取出来的,  字典
        print(request.cookies)
        # 2 加代理
        request.meta['proxy']=self.get_proxy()   # 从代理池中获取一个
        print(request.meta['proxy'])
        # 3 修改ua
        from fake_useragent import UserAgent   # ua模块,随机获取一个
        ua = UserAgent(verify_ssl=False)
        request.headers['User-Agent']=ua.random
        print(request.headers)
# 代理池
def get_proxy(self):
    import requests
    ret=requests.get('http://0.0.0.0:5010/get').json()['proxy']
    print(ret)
    return ret
        return None

十、集成selenium

#可在两个地方集成。
#1.process_request(请求出去的时候)  # 推荐写这里,少请求一次。直接集成封装
#2.process_response(请求回来的时候) # 不推荐,因为夺走了一次请求,回来再集成封装
# 方案一:缺点很大。每次一请求都要打开一个bro浏览器
def process_request(self, request, spider):
    from selenium import webdriver
    from scrapy.http import HtmlResponse
    bro = webdriver.Chrome(executable_path='../chromedriver')
    bro.get(request.url)
    text = bro.page_source
    response = HtmlResponse(url=request.url, body=text.encode('utf-8'), status=200)
    return response
# 方案二:改进为一开始就打开一个bro浏览器,后面都用这一个bro
class CnblogsSpider(scrapy.Spider):
    name = 'cnblogs'
    from selenium import webdriver
    # 在爬虫一开始就打开bro对象
    bro = webdriver.Chrome(executable_path='../chromedriver')  
    # 在爬虫中新添加的方法:关闭bro
    def close(spider, reason):
    	spider.bro.close()  # 爬虫结束关闭
# 中间件中
def process_request(self, request, spider):
    from scrapy.http import HtmlResponse
    spider.bro.get(request.url)  # 每个请求使用一个bro
    text = spider.bro.page_source
    response = HtmlResponse(url=request.url, body=text.encode('utf-8'), status=200)
    return response

十一、指纹和布隆过滤器实现增量爬取

什么是增量爬取?

-增量爬取(100链接,150个链接)

  • -已经爬过的,放到某个位置(mysql,redis中:集合)
  • -如果用默认的,爬过的地址,放在内存中,只要项目一重启,就没了,它也不知道我爬过那个了,所以要自己重写去重方案

-你写的去重方案,占得内存空间更小

    -bitmap方案

    -BloomFilter布隆过滤器

网址指纹

# 一、网址指纹
from scrapy.http import Request
from scrapy.utils.request import request_fingerprint
# 这种网址是一个
request1 = Request(url='https://www.baidu.com/s?name=jeff&age=18')
request2 = Request(url='https://www.baidu.com/s?age=18&name=jeff')
ret1=request_fingerprint(requests1)
ret2=request_fingerprint(requests2)
print(ret1) # 6961985868392ae44c15ada494ddeda856cf75fc
print(ret2) # 6961985868392ae44c15ada494ddeda856cf75fc

布隆过滤器

# 安装
# 1.需要先安装bitarray  #下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/
# 2.下载好之后 pip3 install 文件拖进去
# 3.pip3 install pybloom_live
#ScalableBloomFilter 可以自动扩容
from pybloom_live import ScalableBloomFilter
bloom = ScalableBloomFilter(initial_capacity=100, error_rate=0.001, mode=ScalableBloomFilter.LARGE_SET_GROWTH)
url = "https://www.baidu.com/s?name=jeff&age=18"
url2 = "https://www.baidu.com/s?age=18&name=jeff"
bloom.add(url)
print(url in bloom)
print(url2 in bloom)

使用一:添加网址(不推荐)

#BloomFilter 是定长的
from pybloom_live import BloomFilter
bf = BloomFilter(capacity=1000)
url='www.baidu.com'
bf.add(url)
print(url in bf)
print("www.liuqingzheng.top" in bf)

使用二:添加网址指纹(推荐),配合指纹使用

from scrapy.http import Request
from scrapy.utils.request import request_fingerprint
from pybloom_live import BloomFilter
request1 = Request(url='https://www.baidu.com/s?name=jeff&age=18')
request2 = Request(url='https://www.baidu.com/s?age=18&name=jeff')
ret1=request_fingerprint(request1)
ret2=request_fingerprint(request2)
print(ret1) # 6961985868392ae44c15ada494ddeda856cf75fc
print(ret2) # 6961985868392ae44c15ada494ddeda856cf75fc
bf = BloomFilter(capacity=1000) # 1000容量
bf.add(ret2)
if ret1 in bf:
    print('已经爬过此网站,True')
else:
    bf.add(ret1)  # 添加
    print('还没有爬过此网站,返回false')

十二、分布式爬虫

github地址:https://github.com/rmax/scrapy-redis
# 1 安装pip3 install scrapy-redis
# 源码部分,不到1000行,
# 1 原来的爬虫继承
from scrapy_redis.spiders import RedisSpider
class CnblogsSpider(RedisSpider):
  	#start_urls = ['http://www.cnblogs.com/']
    redis_key = 'myspider:start_urls'  # 起始地址为空,在redis中拿
# 2 在setting中配置
  SCHEDULER = "scrapy_redis.scheduler.Scheduler"
  DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
  ITEM_PIPELINES = { 
     'chouti.pipelines.Pipeline': 300,               # 用自己的入库类,比如mysql中
     # 'scrapy_redis.pipelines.RedisPipeline': 300  # 存在别人写好的redis入库类
  }
REDIS_PARAMS  = {'password':'123'}   # 如果redis有密码就配置
#其他更多配置见github
# 3 多台机器上启动scrapy
# 4 向reids中发送起始url
redis-cli lpush myspider:start_urls https://www.cnblogs.com

十三、爬虫框架全站爬取使用案例

可以同时启动两个爬虫,爬不同的网站。但是建议爬不同的网站新建项目

chouti.py 爬虫:

import scrapy
from chouti.items import ChoutiItem  # 导入模型类
class ChoutiaaSpider(scrapy.Spider):
    name = 'choutiaa'
    # allowed_domains = ['https://dig.chouti.com/']   # 允许爬取的域
    start_urls = ['https://dig.chouti.com//']   # 起始爬取位置
    # 解析,请求回来,自动执行parse,在这个方法中解析
    def parse(self, response):
        print('----------------',response)
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(response.text,'lxml')
        div_list = soup.select('.link-con .link-item')
        for div in div_list:
            content = div.select('.link-title')[0].text
            href = div.select('.link-title')[0].attrs['href']
            id = div.attrs['data-id']
            item = ChoutiItem()  # 生成模型对象
            item['content'] = content  # 添加值
            item['href'] = href
            item['id'] = id
            yield item  # 必须用yield

cnblogs.py 爬虫:

# -*- coding: utf-8 -*-
import scrapy
from bs4 import BeautifulSoup
from chouti.items import CnblogsItem  # 导入模型类
from scrapy.http import Request
class CnblogsSpider(scrapy.Spider):
    name = 'cnblogs'
    start_urls = ['https://www.cnblogs.com/']
    def parse(self, response):
        print('------', response)
        soup = BeautifulSoup(response.text, 'lxml')
        div_list = soup.select('#post_list .post_item')
        for div in div_list:
            author = div.select('.post_item_foot a')[0].text
            content_url = div.select('h3 a')[0].attrs['href']
            title = div.select('h3')[0].text
            content_summary = div.select('p')[0].text
            item = CnblogsItem()
            item['author'] = author
            item['content_url'] = content_url
            item['title'] = title
            item['content_summary'] = content_summary
            # print(f'''
            # 作者:{author}
            # 文章地址:{content_url}
            # 标题:{title}
            # 文章内容:{content_summary}
            # ''')            
            # 继续往深一层爬取,传递给content_parse
            yield Request(content_url, callback=self.content_parse, meta={'item': item})
        # 获取下一页的标签网址
        next = soup.select('#paging_block > div > a:nth-last-child(1)')[0].attrs['href']
        next = 'https://www.cnblogs.com/'+next
        yield Request(next)   # 继续爬取下一页
    def content_parse(self, response):
        item = response.meta.get('item')
        content = response.css('#cnblogs_post_body').extract_first()
        if not content:
            content = response.css('content').extract_first()
        item['content'] = content
        # print(item)
        yield item

items.py 模型类:

# -*- coding: utf-8 -*-
# Define here the models for your scraped items
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html
import scrapy
class ChoutiItem(scrapy.Item):
    content = scrapy.Field()
    href = scrapy.Field()
    id = scrapy.Field()
class CnblogsItem(scrapy.Item):
    author = scrapy.Field()
    content_url = scrapy.Field()
    title = scrapy.Field()
    content_summary = scrapy.Field()
    content = scrapy.Field()

pipelines.py 数据持久化文件

# -*- coding: utf-8 -*-
# Define your item pipelines here
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# 保存到文件
class Pipeline(object):
    def open_spider(self, spider):
        # choutiaa爬虫入库前
        if spider.name == 'choutiaa':
            # 一开始就打开文件
            self.f = open('a.txt', 'w', encoding='utf-8')
        # cnblog爬虫入库前
        elif spider.name == 'cnblogs':
            import pymysql
            self.conn = pymysql.Connect(host='127.0.0.1', port=3306, db='cnblogs', user='root', password="123",autocommit=True)
    def process_item(self, item, spider):
        # choutiaa爬虫入库中
        if spider.name == 'choutiaa':
            # 写入文件的操作
            self.f.write(item['content'])
            self.f.write(item['href'])
            self.f.write(item['id'])
            self.f.write('\n')
            return item
        # cnblog爬虫入库中
        elif spider.name == 'cnblogs':
            print('cnblogs入库中')
            curser = self.conn.cursor()
            sql = 'insert into article (author,content_url,title,content_summary,content) values (%s,%s,%s,%s,%s)'
            curser.execute(sql, (
            item['author'], item['content_url'], item['title'], item['content_summary'], item['content']))
    def close_spider(self, spider):
        # choutiaa爬虫入库结束
        if spider.name == 'choutiaa':
            # 写入完毕,最后关闭文件
            self.f.close()
        # cnblog爬虫入库结束
        elif spider.name == 'cnblogs':
            print('cnblogs入库完毕')
            self.conn.close()

main.py

from scrapy.cmdline import execute
# execute(['scrapy','crawl','choutiaa'])
execute(['scrapy','crawl','cnblogs'])

以上就是scarpy爬虫框架集成selenium及详细讲解的详细内容!

Python 相关文章推荐
python开发之文件操作用法实例
Nov 13 Python
python 文件操作api(文件操作函数)
Aug 28 Python
python检测空间储存剩余大小和指定文件夹内存占用的实例
Jun 11 Python
python 自动重连wifi windows的方法
Dec 18 Python
Django 内置权限扩展案例详解
Mar 04 Python
在VS2017中用C#调用python脚本的实现
Jul 31 Python
python中sort和sorted排序的实例方法
Aug 26 Python
python发qq消息轰炸虐狗好友思路详解(完整代码)
Feb 15 Python
Python图像处理库PIL的ImageFilter模块使用介绍
Feb 26 Python
python修改linux中文件(文件夹)的权限属性操作
Mar 05 Python
matplotlib制作雷达图报错ValueError的实现
Jan 05 Python
Python控制台输出俄罗斯方块的方法实例
Apr 17 Python
Python使用华为API为图像设置多个锚点标签
python实现手机推送 代码也就10行左右
Apr 12 #Python
Python内置包对JSON文件数据进行编码和解码
详细介绍python操作RabbitMq
Python selenium绕过webdriver监测执行javascript
Apr 12 #Python
Pillow图像处理库安装及使用
Apr 12 #Python
Python各协议下socket黏包问题原理
Apr 12 #Python
You might like
PHP中获取文件扩展名的N种方法小结
2012/02/27 PHP
PHP检测用户语言的方法
2015/06/15 PHP
php视频拍照上传头像功能实现代码分享
2015/10/08 PHP
Laravel实现批量更新多条数据
2020/04/06 PHP
用JavaScript 处理 URL 的两个函数代码
2007/08/13 Javascript
JS类的封装及实现代码
2009/12/02 Javascript
一样的table?不一样的table(可编辑状态table)
2012/09/19 Javascript
javascript之典型高阶函数应用介绍
2013/01/10 Javascript
javascript级联下拉列表实例代码(自写)
2013/05/10 Javascript
JS根据变量保存方法名并执行方法示例
2014/04/04 Javascript
JS的encodeURI和java的URLDecoder.decode使用介绍
2014/05/08 Javascript
30个经典的jQuery代码开发技巧
2014/12/15 Javascript
JSON+Jquery省市区三级联动
2016/01/13 Javascript
JS高级运动实例分析
2016/12/20 Javascript
Javascript调试之console对象——你不知道的一些小技巧
2017/07/10 Javascript
JS交互点击WKWebView中的图片实现预览效果
2018/01/05 Javascript
这应该是最详细的响应式系统讲解了
2019/07/22 Javascript
解决layUI的页面显示不全的问题
2019/09/20 Javascript
HTML+JS实现“代码雨”效果源码(黑客帝国文字下落效果)
2020/03/17 Javascript
vue 项目引入echarts 添加点击事件操作
2020/09/09 Javascript
Vue自定义表单内容检查rules实例
2020/10/30 Javascript
[03:48]显微镜下的DOTA2第四期——TP动作
2014/06/20 DOTA
跟老齐学Python之编写类之三子类
2014/10/11 Python
在Django中创建第一个静态视图
2015/07/15 Python
详解python while 函数及while和for的区别
2018/09/07 Python
利用ImageAI库只需几行python代码实现目标检测
2019/08/09 Python
tensorflow 实现从checkpoint中获取graph信息
2020/02/10 Python
Python抖音快手代码舞(字符舞)的实现方法
2021/02/07 Python
Gloeilampgoedkoop荷兰:在线购买灯泡
2019/02/16 全球购物
德国BA保镖药房中文网:Bodyguard Apotheke
2021/03/09 全球购物
先进单位事迹材料
2014/12/25 职场文书
求职简历自我评价怎么写
2015/03/10 职场文书
2015年维修电工工作总结
2015/04/25 职场文书
学校社团活动总结
2015/05/07 职场文书
2019餐饮行业创业计划书!
2019/06/27 职场文书
python基础入门之字典和集合
2021/06/13 Python