Scrapy+seleninu抓取内容同时下载图片几个问题

使用了Scrapy+Seleninm+Scrapy_redis抓取了详情页的内容和图片,贴出需要完善和出问题的代码,做部分解析和说明。

# -*- coding: utf-8 -*-import time;

from scrapy.linkextractors import LinkExtractor from scrapy.spiders import Rulefrom scrapy_redis.spiders import RedisCrawlSpider #导入RedisCrawSpider,以便使用Scrapy_redis实现1任务队列持久化(可支持暂停或重启爬虫)和2进行重复过滤
from selenium import webdriver;#导入seleninum的Webdriver,以调用无界流利器,实现动态内容的的获取,本文用的是Chrome,当然可以用非常多的浏览器,可以看看源码,支持很多的from selenium.webdriver.chrome.options import Options #调用Chorme浏览器的启动参数选项

from scrapyYF.items import ScrapyyfItem

class YaofangSpider(RedisCrawlSpider):    name = ‘yaofang‘    allowed_domains = [‘www.jian.com‘]    start_urls = [‘https://www.jian.com/‘]    redis_key = ‘JK:YP‘    # 必须是列表    rules = [        # follow=False(不跟进), 只提取首页符合规则的url,然后爬取这些url页面数据,callback解析        # Follow=True(跟进链接), 在次级url页面中继续寻找符合规则的url,如此循环,直到把全站爬取完毕        # Rule(LinkExtractor(allow=(r‘\/c\/category\?cat_id=\d*$‘)),follow=True),#要想抓取更多,可以同时放开此项,从分类页也可以找相应的内容        Rule(LinkExtractor(allow=(r‘\/product\/\d*.html$‘), unique=True), callback=‘parse_druginfo‘, follow=True)        # Rule(LinkExtractor(allow=(r‘\/product\/11929.html‘), unique=True), callback=‘parse_druginfo‘, follow=False)        # Rule(LinkExtractor(allow=(r‘\/article\/\d*$‘),unique=True), callback=‘parse_item‘, follow=True)    ]

    def __init__(self, *args, **kwargs):        super(YaofangSpider, self).__init__(*args, **kwargs)#如果不调用父类的这个,会出现AttributeError: ‘xxxSpider‘ object has no attribute ‘_rules‘的错误        chrome_opt = Options();  # 创建参数设置对象.        chrome_opt.add_argument(‘--headless‘);  # 无界面化.        chrome_opt.add_argument(‘--disable-gpu‘);  # 配合上面的无界面化.        chrome_opt.add_argument(‘--disable-infobars‘);  # 配合上面的无界面化.        chrome_opt.add_argument(‘--window-size=1366,768‘);  # 设置窗口大小, 窗口大小会有影响.        chrome_opt.add_argument(‘blink-settings=imagesEnabled=false‘);  # 禁止加载图片        # self.bro=webdriver.Chrome(executable_path=r‘D:\Python27\Scripts\chromedriver.exe‘)        self.bro = webdriver.Chrome(chrome_options=chrome_opt);

    def parse_druginfo(self, response):        item = ScrapyyfItem();        item[‘from_url‘] = response.url;        item[‘addtime‘] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime());        item[‘updated‘] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime());        item[‘class_name‘] = response.xpath(            ‘normalize-space(//div[@class="crumb"]/div/a[2]/text())‘).extract_first() + ‘_‘ + response.xpath(            ‘normalize-space(//div[@class="crumb"]/div/a[3]/text())‘).extract_first();  # 分类,比如:中西药品_男科药品 extract_first是提取第一个内容,python3以上已经用get()来代替了getall=extract,get=extract_first        item[‘goods_id‘] = "jianke_" + response.xpath(            ‘normalize-space(//dl[@class="assort"][1]/dd/text())‘).extract_first();  # 来源+唯一标识,比如:jianke_B13003000675        item[‘drug_name‘] = response.xpath(            ‘normalize-space(//dl[@class="assort tongyong"]/dd/a/text())‘).extract_first();  # 药品名称:六味地黄丸        item[‘goods_name‘] = response.xpath(            ‘normalize-space(//div[@class="det_title"]//h1/text())‘).extract_first();  # 商品名称:同仁堂 六味地黄丸(浓缩丸) 120s        item[‘grant_number‘] = response.xpath(            ‘normalize-space(//dl[@class="assort"][2]/dd/span/text())‘).extract_first();  # ‘批准文号‘        item[‘ingredient‘] = response.xpath(            u"normalize-space(//*[@id=‘b_1_1‘]/table//tr[contains(td,‘主要原料‘)]/td[2]/text())").extract_first();  # 主要成份:熟地黄、酒萸肉、牡丹皮、山药、茯苓、泽泻。xpath提取标题为"主要原料"后的内容        item[‘indiction‘] = response.xpath(            u"normalize-space(//*[@id=‘b_1_1‘]/table//tr[contains(td,‘主要作用‘)]/td[2]/text())").extract_first();  # 主要作用:滋阴补肾。用于肾阴亏损,头晕耳鸣,腰膝酸软,骨蒸潮热,盗汗遗精。        item[‘standard‘] = response.xpath(            u‘normalize-space(//*[@id="b_1_1"]/table//tr[td="产品规格"]/td[2]/text())‘).extract_first();  # 产品规格:120丸(浓缩丸)        item[‘usages‘] = response.xpath(            u‘normalize-space(//*[@id="b_1_1"]/table//tr[td="用法用量"]/td[2]/text())‘).extract_first();  # 用法用量:口服。一次8丸,一日3次。        item[‘manual‘] = "".join(response.xpath(u‘//div[@id="b_2_2"]/div/child::p‘).extract());  # 抓取说明书的内容        item[‘imgsrc‘] = response.xpath(u‘//div[@id="tb21"]/div//child::img/@src‘).extract();        item[‘manufacturer‘] = response.xpath(            u‘normalize-space(//*[@id="b_1_1"]/table//tr[td="生产企业"]/td[2]/text())‘).extract_first();  # 生产企业:北京同仁堂科技发展股份有限公司制药厂        yield item;

    def __del__(self):        self.bro.quit();

  代码总结:

  •  使用RedisCrawSpider,要导入Scrapy_redis可以实现1任务队列持久化(可支持暂停或重启爬虫)和2进行重复过滤
  • 使用CrawlSpider或RedisCrawSpider,如果重构_init函数时,一定要调用父类函数,不然会报AttributeError: ‘xxxSpider‘ object has no attribute ‘_rules‘的错误
  •   使用selenium调用webdriver以使用无界浏览器时,可以调好多无界浏览器,比如:chrome,firefox,safari等,并能设置相应的启动参数.具体,可以看https://www.cnblogs.com/jessicor/p/12072255.html
  •  extract_first是提取第一个内容,python3以上已经用get()来代替了getall=extract,get=extract_first
  • xpath提取标题为"主要原料"后的内容//*[@id=‘b_1_1‘]/table//tr[contains(td,‘主要原料‘)]/td[2]/text()
class safetyChainMiddleware(object):    def process_request(self, request, spider):        request.headers[‘User_Agent‘] = user_agent.generate_user_agent()#调用user_agent生成随机headers头,防止被封        referer = request.url        if referer:            request.headers[‘Referer‘] = referer#生成头信息Referer,以防止被封

class seleniumMiddleware(object):    def isFindElement(self, spider):        try:            # spider.bro.find_element_by_id(‘b_2‘).click();            if WebDriverWait(spider.bro, 3).until(                    EC.text_to_be_present_in_element((By.XPATH, "//ul/li[@id=‘b_2‘]"), u‘说明书‘)):#每0.05ms请求一次,请求3s钟,判断id=b_2,标题等于说明书的元素是否存在,存在则执行下边的模拟单击动作                spider.bro.find_element_by_xpath(u"//ul/li[@id=‘b_2‘ and contains(text(),‘说明书‘)]").click();            pass        except:            # spider.bro.quit()            pass    def process_response(self, request, response, spider):        url = request.url        if string.find(url, ‘.jpg‘) != -1:#如果是图片,直接返回response,不能用HtmlResponse,不然图片不能正常返回或下载            return response        else:            spider.bro.get(request.url)

            return HtmlResponse(url=spider.bro.current_url, body=page_text, encoding=‘utf8‘, request=request)#返回无界浏览器返回的response内容信息.
  • 添加自定义中间件,为了防止被封,一般要添加的是user_agent,proxy,referer和cookie,要注意,一定要在process_requess里处理,另外还要注意这个函数的返回值.不同的返回值,会执行不同操作:

    

当每个request通过下载中间件时,该方法被调用。

process_request() 必须返回其中之一: 返回 None 、返回一个 Response 对象、返回一个 Request 对象或raise IgnoreRequest 。

如果其返回 None ,Scrapy将继续处理该request,执行其他的中间件的相应方法,直到合适的下载器处理函数(download handler)被调用, 该request被执行(其response被下载)。

如果其返回 Response 对象,Scrapy将不会调用 任何 其他的 process_request() 或 process_exception() 方法,或相应地下载函数; 其将返回该response。 已安装的中间件的 process_response() 方法则会在每个response返回时被调用。

如果其返回 Request 对象,Scrapy则停止调用 process_request方法并重新调度返回的request。当新返回的request被执行后, 相应地中间件链将会根据下载的response被调用。

如果其raise一个 IgnoreRequest 异常,则安装的下载中间件的 process_exception() 方法会被调用。如果没有任何一个方法处理该异常, 则request的errback(Request.errback)方法会被调用。如果没有代码处理抛出的异常, 则该异常被忽略且不记录(不同于其他异常那样)。

  • process_response,这个处理response,针对图片,一定要单独返回.不要用htmlResponse.这个是无界浏览器返回的内容.我在这儿是做了判断.不然图片不能下载.纠结了好几天,最后好好看了看文档,Step by step若干遍程序,终于找到了原因.scrapy的执行流程很重要.
    process_response的返回值也需要说明下
      

process_request() 必须返回以下之一: 返回一个 Response 对象、 返回一个 Request 对象或raise一个 IgnoreRequest 异常。

如果其返回一个 Response (可以与传入的response相同,也可以是全新的对象), 该response会被在链中的其他中间件的 process_response() 方法处理。

如果其返回一个 Request 对象,则中间件链停止, 返回的request会被重新调度下载。处理类似于 process_request() 返回request所做的那样。

如果其抛出一个 IgnoreRequest 异常,则调用request的errback(Request.errback)。 如果没有代码处理抛出的异常,则该异常被忽略且不记录(不同于其他异常那样)。

 

原文地址:https://www.cnblogs.com/jessicor/p/12109089.html

时间: 2024-10-14 19:20:45

Scrapy+seleninu抓取内容同时下载图片几个问题的相关文章

一个简单的scrapy爬虫抓取豆瓣刘亦菲的图片地址

一.第一步是创建一个scrapy项目 sh-3.2# scrapy startproject liuyifeiImage sh-3.2# chmod -R 777 liuyifeiImage/ 二.分析图片特征 1.解决分页url部分: 我们爬虫的start_url是"http://movie.douban.com/celebrity/1049732/photos/?type=C&start=0&sortby=vote&size=a&subtype=a"

Python快速开发分布式搜索引擎Scrapy精讲—编写spiders爬虫文件循环抓取内容

编写spiders爬虫文件循环抓取内容 Request()方法,将指定的url地址添加到下载器下载页面,两个必须参数, 参数: url='url' callback=页面处理函数 使用时需要yield Request() parse.urljoin()方法,是urllib库下的方法,是自动url拼接,如果第二个参数的url地址是相对路径会自动与第一个参数拼接 # -*- coding: utf-8 -*- import scrapy from scrapy.http import Request

第三百四十一节,Python分布式爬虫打造搜索引擎Scrapy精讲—编写spiders爬虫文件循环抓取内容—

第三百四十一节,Python分布式爬虫打造搜索引擎Scrapy精讲-编写spiders爬虫文件循环抓取内容- 编写spiders爬虫文件循环抓取内容 Request()方法,将指定的url地址添加到下载器下载页面,两个必须参数, 参数: url='url' callback=页面处理函数 使用时需要yield Request() parse.urljoin()方法,是urllib库下的方法,是自动url拼接,如果第二个参数的url地址是相对路径会自动与第一个参数拼接 # -*- coding:

使用python scrapy框架抓取cnblog 的文章内容

scrapy 的文档请移驾到 http://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/install.html 1.准备工作  安装python .Spyder .scrapy 如果想要数据直接入mysql 还需要安装python的 MySQLdb 依赖包 本人mac操作系统 安装MySQLdb的时候出现了些小问题  最后是重装了openssl 才通过的 Spyder 是编写python的ide 2.新建项目  cd /usr/local/var/ww

python实现爬虫(一)--- Scrapy框架抓取豆瓣书籍信息

Scrapy是一个用python实现都爬虫框架,简单易用,功能强大,只需要在框架的基础上自定义自己的分析规则即可,具体如何新建工程等待都在官方文档上面讲解得非常清楚,官方文档tutorial(http://doc.scrapy.org/en/latest/intro/tutorial.html)请保证下载较新版本的Scrapy(我的是0.24.2,scrapy -v)旧版本会出现一些问题. 下面我使用Scrapy抓取豆瓣上面编程书籍的一些简单信息 一.准备爬取的页面如下,新建一个douban工程

PHP利用Curl实现多线程抓取网页和下载文件

PHP 利用 Curl  可以完成各种传送文件操作,比如模拟浏览器发送GET,POST请求等等,然而因为php语言本身不支持多线程,所以开发爬虫程序效率并不高,一般采集 数据可以利用 PHPquery类来采集数据库,在此之外也可以用 Curl ,借助Curl 这个功能实现并发多线程的访问多个url地址以实现并发多线程抓取网页或者下载文件. 至于具体实现过程,请参考下面几个例子: 1.实现抓取多个URL并将内容写入指定的文件 $urls = array( '路径地址', '路径地址', '路径地址

Python抓取网页中的图片到本地

今天在网上找了个从网页中通过图片URL,抓取图片并保存到本地的例子: 1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 # Author: xixihuang 5 # Date : 2016/08/28 10:12 AM 6 # Desc: 抓取网页,获取图片URL,抓取图片内容并保存到本地. 7 8 import os 9 import uuid 10 import urllib2 11 import cookielib 12 '''获取

scrapy递归抓取网页数据

scrapy spider的parse方法可以返回两种值:BaseItem,或者Request.通过Request可以实现递归抓取. 如果要抓取的数据在当前页,可以直接解析返回item(代码中带**注释的行直接改为yield item): 如果要抓取的数据在当前页指向的页面,则返回Request并指定parse_item作为callback: 如果要抓取的数据当前页有一部分,指向的页面有一部分(比如博客或论坛,当前页有标题.摘要和url,详情页面有完整内容)这种情况需要用Request的meta

Python抓取网页&批量下载文件方法初探(正则表达式+BeautifulSoup) (转)

Python抓取网页&批量下载文件方法初探(正则表达式+BeautifulSoup) 最近两周都在学习Python抓取网页方法,任务是批量下载网站上的文件.对于一个刚刚入门python的人来说,在很多细节上都有需要注意的地方,以下就分享一下我在初学python过程中遇到的问题及解决方法. 一.用Python抓取网页 基本方法: [python] view plaincopyprint? import urllib2,urllib url = 'http://www.baidu.com' req