病毒样本快到碗里来,一个样本下载爬虫的实现


简介

Malwar是一个使用了Cuckoo Sanbox的在线恶意软件分析系统,由于它提供一些病毒样本下载,就想能不能写个爬虫把样本下下来。顺便写篇博客记录下。
页面分析

打开 https://malwr.com/analysis ,我们可以当前页看到有TimeStamp、md5、文件名、文件类型和杀软查杀数,下一页类似。
图片说明

只有MD5的超链接可以点,点进去看看,
图片说明

我写这个的爬虫的目的是下载样本,只关心样本的下载地址,并不关心其他的信息。

现在我们可以理清下思路:

   获取每一页的网页源码
   解析当前页的每一个md5对应的详细信息链接
   在详细信息页面解析下载地址。

提取规则

先从第一页开始爬起

from scrapy.spiders import CrawlSpider
from scrapy.http import Request
from malwr.items import MalwrItem
from scrapy.selector import Selector
class BasicSpider(CrawlSpider):
    name = "basic"
    allowed_domains = ["malwr.com"]
    strat_urls = ['https://malwr.com/analysis/?page=1']
    def start_requests(self):
        url = self.strat_urls[0] 
        yield Request(url, callback=self.parse_item)
    def parse_item(self):
         pass

scrapy支持xss选择器和css选择器,一般是用哪个比较方便就用哪个。

图片说明

对应链接的xpath选择器为 //td/a/@href,
图片说明

下一页的链接的xpath选择器为 //a[contains(text(),'Next')]/@href

图片说明

要得到下载地址需要账号登陆,这里先不管它,单击Download下载文件对应的下载链接提取规则xpath选择器

//a[contains(@class,'btn-primary')]/@href.

现在来补充下代码,

def parse_item(self):
      # 当前页所有md5对应的详细页面
      url = response.xpath("//td/a/@href").extract()
      for u in url:
          url = urlparse.urljoin("https://malwr.com",u.encode("utf-8"))
          yield Request(url,self.parse_downurl)
      # 下一页
      nextpage = response.xpath("//a[contains(text(),'Next')]/@href").extract()[0].encode('utf-8')
      url = urlparse.urljoin("https://malwr.com",nextpage)
      yield Request(url,self.parse_item) 
#解析下载地址
def parse_downurl(self):
      pass

登陆

之前写爬虫的时候,是可以直接通过post登陆的,而我开始写这篇文章的时候开始加上了google的ReCaptcha验证码。

只能换种方式使用selenium来登陆Malwr.得到登陆后的cookie后,我们就可以用这个cookie开始下载样本了。

from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
def get_cookie():
        loginurl = 'https://malwr.com/account/login/'
        # 当然Ie也可以换成其他的,比如firefox、chrom等等
        driver = webdriver.Ie()
        driver.get(loginurl)
        WebDriverWait(driver,3).until(lambda x:x.find_element_by_link_text('Logout'))
        cookies = driver.get_cookies()
        driver.close()
        return cookies

使用Scrapy有一点很蛋疼,cookie它不会自动传递,需要自己在Request中传递下去,才能使后面的网络请求使用这个cookie.


class BasicSpider(CrawlSpider):
    name = "basic"
    allowed_domains = ["malwr.com"]
    strat_urls = ['https://malwr.com/analysis/?page=1']
    custom_settings = {
                    "COOKIES":get_cookie(),
                    }
    def start_requests(self):
        url = self.strat_urls[0]
        # cookiejar  cookie传递
        yield Request(url,cookies=self.custom_settings['COOKIES'],
                          callback=self.parse_item,meta = {'cookiejar' : 1})
    def parse_item(self,response):
          # 当前页所有md5对应的详细页面
          url = response.xpath("//td/a/@href").extract()
          for u in url:
              url = urlparse.urljoin("https://malwr.com",u.encode("utf-8"))
              yield Request(url,self.parse_downurl,meta = {'cookiejar' : 1})
          # 下一页
          nextpage = response.xpath("//a[contains(text(),'Next')]/@href").extract()[0].encode('utf-8')
          url = urlparse.urljoin("https://malwr.com",nextpage)
          yield Request(url,self.parse_item,meta = {'cookiejar' : 1})

我们在start_request函数里获取到登陆后的cookie,使用meta = {'cookiejar' : 1}将cookie传递到parse_item函数。

parse_item函数的Request的两个Request也加上cookiejar,一个把cookie传给parse_item,一个传给parse_downurl,
下载样本

scrapy本身就已经为我们提供了很好的文件下载、图片下载的功能,

修改custom_settings,加上我们要用的ITEM_PIPELINES(在这里面实现下载功能)和FILES_STORE(保存到的文件夹)

custom_settings = {
                  "COOKIES":get_cookie(),
                  'ITEM_PIPELINES':{'malwr.pipelines.MalwrPipeline':1},
                  "FILES_STORE":"E:\\Virus\\Malwr"
                  }

FilesPipeline是从file_urls中拿到下载地址然后开始下载文件,因此我们还需要Item.py定义一个file_urls.

# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class MalwrItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    file_urls = scrapy.Field()

在piplines.py文件实现文件的下载方法,继承FilesPipeline下载文件。

由于下载文件需要cookie,因此重写了构造函数和get_media_requests函数,在Request中加上了cookies参数.

我们在custom_settings中保存了cookie,这里直接使用getlist拿到登陆后的cookie.

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
from scrapy.http import Request
from scrapy.pipelines.files import FilesPipeline
class MalwrPipeline(FilesPipeline):
    cookies = []
    def __init__(self, store_uri, download_func=None, settings=None):
        super(MalwrPipeline,self).__init__(store_uri, download_func,settings)
        self.cookies = settings.getlist("COOKIES")
    # 开始下载文件
    def get_media_requests(self, item, info):
        for file_url in item['file_urls']:
            yield Request(file_url,cookies=self.cookies)

解析下载地址,将解析到的下载链接列表放入item的file_urls,返回item。pipeline会file_urls拿到链接开始调用get_media_requests下载文件

    def parse_downurl(self,response):
        try:
            # 提取点击下载按钮的下载地址
            url = response.xpath("//a[contains(@class,'btn-primary')]/@href").extract()[0].encode('utf-8')
            url = urlparse.urljoin("https://malwr.com",url)
            item = MalwrItem()
            item['file_urls'] = [url]
            return item
        except Exception,e:
            pass
return

最后附上完整的源码 https://github.com/ydc1992/Malwr

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 简介
  2. 2. 提取规则
  3. 3. 登陆
,