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模拟鼠标拖动操作的方法
Mar 11 Python
最基础的Python的socket编程入门教程
Apr 23 Python
Python常用小技巧总结
Jun 01 Python
梯度下降法介绍及利用Python实现的方法示例
Jul 12 Python
python爬虫之xpath的基本使用详解
Apr 18 Python
python MNIST手写识别数据调用API的方法
Aug 08 Python
浅谈Python爬虫基本套路
Mar 25 Python
Django中信号signals的简单使用方法
Jul 04 Python
Python time库基本使用方法分析
Dec 13 Python
python列表返回重复数据的下标
Feb 10 Python
关于tensorflow softmax函数用法解析
Jun 30 Python
Python基于unittest实现测试用例执行
Nov 25 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
笑谈配置,使用Smarty技术
2007/01/04 PHP
浅谈使用PHP开发微信支付的流程
2015/10/04 PHP
如何简单地用YUI做JavaScript动画
2007/03/10 Javascript
Jquery 学习笔记(一)
2009/10/13 Javascript
C#中TrimStart,TrimEnd,Trim在javascript上的实现
2011/01/17 Javascript
非常漂亮的JS+CSS图片幻灯切换特效
2013/11/20 Javascript
windows8.1+iis8.5下安装node.js开发环境
2014/12/12 Javascript
Jquery中find与each方法用法实例
2015/02/04 Javascript
通过Jquery.cookie.js实现展示浏览网页的历史记录超管用
2015/10/23 Javascript
javascript伸缩菜单栏实现代码分享
2015/11/12 Javascript
JavaScript+html5 canvas制作的百花齐放效果完整实例
2016/01/26 Javascript
基于BootStrap Metronic开发框架经验小结【三】下拉列表Select2插件的使用
2016/05/12 Javascript
Bootstrap模态窗口源码解析
2017/02/08 Javascript
浅谈Fetch 数据交互方式
2018/12/20 Javascript
使用 Vue cli 3.0 构建自定义组件库的方法
2019/04/30 Javascript
ES6中Set和Map用法实例详解
2020/03/02 Javascript
[04:19]DOTA2完美大师赛第四天精彩集锦
2017/11/26 DOTA
python根据路径导入模块的方法
2014/09/30 Python
Python随机生成一个6位的验证码代码分享
2015/03/24 Python
Python中的pass语句使用方法讲解
2015/05/14 Python
快速排序的算法思想及Python版快速排序的实现示例
2016/07/02 Python
python虚拟环境virualenv的安装与使用
2016/12/18 Python
Python 普通最小二乘法(OLS)进行多项式拟合的方法
2018/12/29 Python
pytorch 实现模型不同层设置不同的学习率方式
2020/01/06 Python
Pytorch实现神经网络的分类方式
2020/01/08 Python
利用python查看数组中的所有元素是否相同
2021/01/08 Python
python 实现网易邮箱邮件阅读和删除的辅助小脚本
2021/03/01 Python
详解移动端Html5页面中1px边框的几种解决方法
2018/07/24 HTML / CSS
天猫精选:上天猫,就够了
2016/09/21 全球购物
金讯Java笔试题目
2013/06/18 面试题
销售内勤岗位职责
2014/04/15 职场文书
小学运动会口号
2014/06/07 职场文书
秋季校运会广播稿100字
2014/09/18 职场文书
关于颐和园的导游词
2015/01/30 职场文书
傅雷家书读书笔记
2015/06/29 职场文书
php 解析非标准json、非规范json
2021/04/01 PHP