Scrapy 使用总结

2018-4-8

scrapy 工作流程:engine获得spiders内url,请求调度程序,对url进行爬取,Downloader返回response给爬虫引擎,引擎返回response给spiders,然后spiders处理item,发送给管道处理,然后把结果返回给调度器,然后重复此过程
 一、 首先是Scrapy普通爬虫,没有什么可讲
        
        scrapy startproject name1 //新建Scrapy爬虫项目
        scrapy genspider name2 //新建spider
二、 其次是整站爬虫
        
        scrapy genspider -t crawl lagou www.lagou.com //新建爬虫,自动生成的Spider继承CrawSpider
        在Spider下面会自动生成一个Rule,如:
            rules = (
            Rule(LinkExtractor(allow=r'https://www.lagou.com/jobs/\d+.html'), callback='parse_job', follow=True),
        )
        第一个是正则匹配,只要匹配的链接都会去爬取,然后回调parse_job这个函数,follow=True表示继续跟踪,参数含义看一下源码都能懂,其中还有deny(不匹配什么url)参数等


三、然后爬虫数据需要存入数据库,个人熟悉MySQL等关系型数据库,所以以mysql为主
        a. 爬虫第一步当然是需要把ROBOTSTXT_OBEY改成False,
        b.如果过程总遇到导包问题,应该不出意外需要加这句话
            
            BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
            sys.path.insert(0, os.path.join(BASE_DIR, 'ArticleSpider'))
        c.数据放到数据库需要settings.py里面的ITEM_PIPELINES={....}首先取消注释
        d.然后在items.py内将类对象属性进行处理,建议做的时候线debug一下,以防得到的属性值为数组没转换,对属性处理如下:
    
            job_details = scrapy.Field(
            input_processor=MapCompose(return_value)
            ) 
            其中,return_value是一个自定义的函数,MapCompose()括号内可以填写多个函数进行处理
        当然,如果得到的属性是数组华,可以自动一一个ItemLoader,设置default_output_processor=TakeFirst()即可
       e.然后可以在类里面定义一个插入数据到数据库的函数,例如
         
                 def get_insert_sql(self):
                insert_sql = """
                    insert into lagou(url, job_id, title, salary, job_city, work_years, degree_need, job_type,publish_time,job_desc,crawl_time)
                    VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
                    ON DUPLICATE KEY UPDATE salary=VALUES(salary), work_years=VALUES(work_years),job_desc=VALUES(job_desc)
                """
                params = (self["url"], self["job_id"], self["title"], self["salary"], self["job_city"], self["work_years"]
                          , self["degree_need"], self["job_type"], self["publish_time"], 
                          self["job_desc"],
                          self["crawl_time"].strftime(SQL_DATETIME_FORMAT))
                return insert_sql, params     
        g.然后在Pipeline的process_item内,直接调用
            
          insert_sql, params = item.get_insert_sql()
          self.cursor.execute(insert_sql, params)
          self.conn.commit(
        h.上面这种是同步操作,肯定不是我们想要的,然后twisted就出场了
            
             import MySQLdb
              from twisted.enterprise import adbapi
              import MySQLdb.cursors
              重写from_settings(cls,settings)
              具体代码如下:
              class MySqlTwistedPipelines(object):
                def __init__(self, dbpool):
                    self.dbpool = dbpool
        
                @classmethod
                def from_settings(cls, settings):
                    dbparms = dict(
                        host=settings['MYSQL_HOST'],
                        db=settings['MYSQL_DBNAME'],
                        user=settings['MYSQL_USER'],
                        passwd=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):
                    query = self.dbpool.runInteraction(self.do_insert, item)
                    query.addErrback(self.handler_error)  # 处理异常
            
                def handler_error(self, failure):
                    # 处理异步插入的异常
                    print(failure)
            
                def do_insert(self, cursor, item):
                    insert_sql, params = item.get_insert_sql()
                    cursor.execute(insert_sql, params)
        i. 然后只剩下同步的时候,数据库连接了
            
               def __init__(self):
                self.conn = MySQLdb.connect('127.0.0.1', 'username', 'password', '***_spider', charset='utf8', use_unicode=True)
                self.cursor = self.conn.cursor()
四、数据也放到数据库了,那么需要考虑的问题就是设置User_Agent和ip
         a.如果不设置,那么Scrapy将会自动设置为Scrapy

         b.User_Agent也不能总是一个,如果数据多,实时更换是有必要的,可以选择在setting里面放一个user_agent list,每次随机取,但是这种情况下,每次请求都要执行随机取user_agent的函数。既然Scrapy有Middlewares,就可以利用一个比较好用的user_agent库(fake_useragent,每次随机生成user_agnet),每次在中间件里面process_request(self,request, spider)函数内对headers进行设置user_agent

        c.当然上一步需要把中间件开启,在setting里面取消注释即可,并切需要将scrapy自带的中间件设置为None
            
            'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None
        d.接下来就是动态ip,在西刺网上都是高匿名的ip,不过每次爬取下来然后使用时,发现好多都并不能用,都要先进行访问一下,不能用再筛选,数据不多还可以,数据一旦多起来就慢了。这里使用scrapy_proxies,也是在github上有,同User_Agent设置一样
    
五、接下来就是验证码问题了,tesseract-ocr准确性不高,个人觉得用在线打码方式最方便,当然人工打码准确率是最高的
        a.Selenium集成到Scrapy中,这里就需要信号链了。
        b.同样是操作中间件,在Spider里面,即自己写的爬虫文件里面先init一个browser,然后connect一个信号链来检测爬虫完后关闭浏览器
            
              from scrapy.xlib.pydispatch import dispatcher
              from scrapy import signals
              def __init__(self):
                self.browser = webdriver.Firefox()  # executable_path=""
                super().__init__()
                dispatcher.connect(self.spider_closed, signals.spider_closed)
        c.在中间件里面直接spider.browser获取browser即可
            
            def process_request(self, request, spider):
            if spider.name == "lagou":
                spider.browser.get(request.url)
                import time
                time.sleep(1)
                return HtmlResponse(url=spider.browser.current_url, body=spider.browser.page_source,
                                    encoding="utf-8", request=request)
六、接下来就是phantomjs无界面浏览器继承到scrapy了,和上面类似
七、最后是ElasticSearch了,非关系型数据库,花点时间研究入门也不是很难,用法也是pip install,导包,connect,然后在item里面save一下,当然想要集成到python内使用,需要install的是elasticsearch_dsl,还有elasticsearch_rtf,适合做日志分析系统,爬虫引擎
八、利用scrapyd将爬虫部署,windows上需要在个scrapyd-deploy下新建一个同名的.bat文件,内容是:
        
        @echo off
        "D:\programfiles\python3.6\python.exe" "D:\programfiles\python3.6\Scripts\scrapyd-deploy" %*
九、最后就是爬虫的分布式了,当然用redis
        a.去github clone scrapy-redis放在项目工程中,Spider继承RedisSpider就可以了,简单使用,github都有讲,主要是利调度处理url
十、如有问题,请指出,谢谢
使用Scrapy和Selenium相结合可以实现浏览器模拟操作,实现一些对JavaScript渲染页面的爬取。一旦页面成功加载后,可以将数据传递给Scrapy的Pipeline进一步处理。 要在Scrapy使用Selenium,首先需要在Scrapy的Spider中启用Selenium。可以使用get方法实例化一个Selenium的浏览器对象,并在spider中实现handle_httpresponse方法,在该方法中调用Selenium进行页面渲染,等待JavaScript执行完成后,将渲染后的页面HTML代码返回。 在Spider中进行页面处理后,可以通过yield将数据传递给Scrapy的Pipeline进行进一步处理和存储。Pipeline是Scrapy中的一个处理组件,用于将爬取到的数据进行存储、清洗、筛选或其他处理操作。 要在Pipeline中处理数据,首先需要在settings.py文件中启用Pipeline并设置优先级。然后,在Pipeline文件中实现相应的处理逻辑,例如存储至数据库、保存至本地文件等。 对于使用Selenium渲染的页面数据,可以在Pipeline中进一步处理,例如解析HTML代码、提取指定元素等。可以使用lxml等库对页面进行解析,得到所需的数据。处理完成后,可以进行存储或其他后续操作。 总结来说,使用Scrapy和Selenium结合使用时,可以在Spider中调用Selenium进行页面渲染,等待JavaScript执行完毕后返回渲染后的页面。然后将处理后的数据通过yield传递给Scrapy的Pipeline进行进一步处理和存储。在Pipeline中可以加入特定的处理逻辑,对数据进行解析、存储等操作。这样就实现了Scrapy使用Selenium后调用Pipeline的过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值