V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
luohaha
V2EX  ›  程序员

c 语言写的爬虫,抓取豆瓣上所有科幻电影

  •  5
     
  •   luohaha · 2015-12-24 16:42:38 +08:00 · 9647 次点击
    这是一个创建于 3047 天前的主题,其中的信息可能已经有所发展或是发生改变。

    先给自己定个目标,抓取豆瓣上所有的科幻电影的名称和类型信息,并保存文件。代码越短越好。下面是我的代码:

    #include<cspider/spider.h>
    typedef struct {
      char *getTitle[20];
      char *getDesc[20];
      int size;
    } Movie;
    //开始入口的 url
    char *begin = "www.douban.com/tag/%E7%A7%91%E5%B9%BB/movie";
    void p(cspider_t *cspider, char *d, char *url, void *user_data) {
      Movie *movie = (Movie*)malloc(sizeof(Movie));
      char *urls[20];
      int sizeTitle = xpath(d, "//div[@id='content']/div[@class='grid-16-8 clearfix']/div[@class='article']/div[@class='mod movie-list']/dl/dd/a", movie->getTitle, 20);
      int sizeDesc = xpath(d, "//div[@id='content']/div[@class='grid-16-8 clearfix']/div[@class='article']/div[@class='mod movie-list']/dl/dd/div[@class='desc']", movie->getDesc, 20);
      int sizeUrl = xpath(d, "//div[@id='content']/div[@class='grid-16-8 clearfix']/div[@class='article']/div[@class='paginator']/a/@href", urls, 20);
      movie->size = sizeTitle;
      saveString(cspider, (void*)movie, LOCK);
      char *newUrl[sizeUrl];
      int i;
      //拼接成新的 url
      for (i = 0; i < sizeUrl; i++) {
        newUrl[i] = (char*)malloc(sizeof(char) * (strlen(begin) + strlen(urls[i]) + 1));
        strcat(newUrl[i], begin);
        strcat(newUrl[i], urls[i]);
      }
      //添加新 url 到任务队列
      if (movie->size > 0) {
        addUrls(cspider, newUrl, sizeUrl);
      }
      //回收
      freeStrings(newUrl, sizeUrl);
      freeStrings(urls, sizeUrl);
      freeStrings(movie->getTitle, sizeTitle);
      freeStrings(movie->getDesc, sizeDesc);
      free(movie);
    }
    void s(void *str, void *user_data) {
      Movie *get = (Movie*)str;
      FILE *file = (FILE*)user_data;
      int i;
      for (i = 0; i < get->size; i++) {
        fprintf(file, "名称:%s\n", get->getTitle[i]);
        fprintf(file, "类别:%s\n", get->getDesc[i]);
      }
    }
    int main() {
      cspider_t *spider = init_cspider(); 
      char *agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:42.0) Gecko/20100101 Firefox/42.0";
      char *cookie = "bid=s3/yuH5Jd/I; _pk_ref.100001.8cb4=%5B%22%22%2C%22%22%2C1450940218%2C%22http%3A%2F%2Fmovie.douban.com%2Ftag%2F%22%5D; _pk_id.100001.8cb4=8196f325b29ea5c3.1444265431.9.1450943478.1449364495.; ll=108288; viewed=1130500_24708145_6433169_4843567_1767120_5318823_1899158_1271597; __utma=30149280.927537245.1446813674.1449139583.1450940286.5; __utmz=30149280.1450940286.5.5.utmcsr=book.douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/; ps=y; [email protected]; push_noty_num=0; push_doumail_num=7; ap=1; _pk_ses.100001.8cb4=*; gr_user_id=5f4ee24f-d7bc-4b0b-9322-ceb1d208ee36; __utmb=30149280.17.10.1450940286; __utmc=30149280; ct=y; as=http://www.douban.com/tag/%E7%A7%91%E5%B9%BB/movie";
      cs_setopt_url(spider, begin);
      cs_setopt_useragent(spider, agent);
      cs_setopt_cookie(spider, cookie);
      FILE *file = fopen("./movies.txt", "wb+");
      //指向自定义的解析函数,和数据持久化函数
      cs_setopt_process(spider, p, NULL);
      cs_setopt_save(spider, s, file);
      return cs_run(spider);
    }
    

    一共 60 行左右,还可以。就是得手动回收内存,还有字符串处理,这两点使得代码比较丑陋,和 python 和 java 没得比。我用的爬虫框架是cspider。大家觉得,如果要让这个爬虫框架更完善,让我们用 c 写爬虫更爽,还需要实现什么呢?

    第 1 条附言  ·  2015-12-25 15:38:17 +08:00

    cspider 的项目地址在 https://github.com/luohaha/CSpider ,欢迎来 star 和 fork !

    第 2 条附言  ·  2015-12-25 15:49:20 +08:00

    cspider 爬虫框架的目标就是让我们用 c 语言写爬虫时,能像用 python 写爬虫那么方便。虽然道路遥远~~

    第 3 条附言  ·  2015-12-25 22:52:34 +08:00
    多谢几位好心人提醒,豆瓣下逐页抓取是获取不到完整的豆瓣电影的,所以上述方法并不能获取到所有的科幻电影。。
    54 条回复    2016-01-01 18:32:21 +08:00
    TJT
        1
    TJT  
       2015-12-24 17:00:22 +08:00 via Android   ❤️ 1
    然后你就这么随便把 cookie 发上来了?
    luohaha
        2
    luohaha  
    OP
       2015-12-24 17:06:48 +08:00
    @TJT 忘了删了。。。
    zhy
        3
    zhy  
       2015-12-24 17:21:28 +08:00
    楼主自己写的,别不好意思嘛 -.-
    mzer0
        4
    mzer0  
       2015-12-24 17:39:17 +08:00 via iPhone
    cookie 怎么来的?
    luohaha
        5
    luohaha  
    OP
       2015-12-24 17:48:59 +08:00
    @mzer0 浏览器上
    mzer0
        6
    mzer0  
       2015-12-24 17:52:31 +08:00 via iPhone
    @luohaha 万一用的是 session 怎么办
    luohaha
        7
    luohaha  
    OP
       2015-12-24 18:44:44 +08:00
    @mzer0 这里用 cookie 是因为豆瓣会给没有 cookie 的客户端返回 403 。。
    luohaha
        8
    luohaha  
    OP
       2015-12-24 18:47:19 +08:00
    @zhy 哈哈
    jise
        9
    jise  
       2015-12-24 21:11:26 +08:00
    Mark~
    yxzblue
        10
    yxzblue  
       2015-12-24 23:35:01 +08:00
    厉害!
    just1
        11
    just1  
       2015-12-24 23:44:02 +08:00 via Android
    @mzer0 session 只是时效性,到期换一个不就好了
    jugelizi
        12
    jugelizi  
       2015-12-25 00:00:37 +08:00
    楼主的 QQ 哈啊哈
    oojiayu
        13
    oojiayu  
       2015-12-25 00:11:38 +08:00
    fxxkgw
        14
    fxxkgw  
       2015-12-25 08:55:41 +08:00
    学习了。
    quietin
        15
    quietin  
       2015-12-25 10:22:18 +08:00
    网页上带页码下标的并不是它的所有电影。。。
    luohaha
        16
    luohaha  
    OP
       2015-12-25 11:27:13 +08:00
    @quietin 什么意思?我抓取的是豆瓣上分类为科幻的所有的电影。
    luohaha
        17
    luohaha  
    OP
       2015-12-25 11:27:36 +08:00
    @oojiayu 。。求不调戏。
    zyearn
        18
    zyearn  
       2015-12-25 12:07:00 +08:00   ❤️ 1
    之前用 C++写过一个基于事件的知乎爬虫,底层全部纯手写,不依赖任何库,有兴趣的可以看看... https://github.com/zyearn/zhihuCrawler
    glogo
        19
    glogo  
       2015-12-25 12:58:43 +08:00
    233333
    quietin
        20
    quietin  
       2015-12-25 13:04:34 +08:00
    @luohaha 我的意思是网页结构解析的电影只是分类下的一部分而已,豆瓣并没有把某一分类下的所有电影暴露出来
    jise
        21
    jise  
       2015-12-25 13:31:26 +08:00 via Android
    @zyearn c++面向对象的特征和强大 stl 使得结构设计,以及字符串处理等方面要远方便于纯 c.
    luohaha
        22
    luohaha  
    OP
       2015-12-25 15:09:17 +08:00
    @quietinwww.douban.com/tag/%E7%A7%91%E5%B9%BB/movie 这里是科幻电影的第一页,爬虫爬取这一页后,在这页的底部会有其它页的链接,爬虫会将这些链接再次加入任务队列,继续往下抓取。因为提供了 bloom filter ,所以也不用担心会有重复 url 的问题。
    pypy
        23
    pypy  
       2015-12-25 15:14:58 +08:00
    求教: C 写爬虫的优势在哪儿?
    luohaha
        24
    luohaha  
    OP
       2015-12-25 15:29:23 +08:00
    @pypy 说实话,在爬虫这种探索式的应用场景下, c 语言并不合适。
    pypy
        25
    pypy  
       2015-12-25 15:36:58 +08:00
    @luohaha 所以你用 C 写爬虫只是为了练手吗?准备未来将 C 应用到什么场景呢?
    luohaha
        26
    luohaha  
    OP
       2015-12-25 15:41:41 +08:00
    @pypy 我做了一个 c 语言的爬虫框架 cspider ,上面这个爬虫就是用 cspider ( https://github.com/luohaha/CSpider )写的。做 cspider 的目的就是要让我们用 c 语言写爬虫时也能够像 python 一样方便和高效。当然,这个框架好比较早期,现阶段离目标还比较远,还需要不断地努力和完善。
    quietin
        27
    quietin  
       2015-12-25 16:45:50 +08:00
    @luohaha 我的意思就是你把下面那页码都抓了也不是全部的,你自己看看那链接的 start ,连 1000 都不到就不给你数据了
    luohaha
        28
    luohaha  
    OP
       2015-12-25 16:57:01 +08:00
    @quietin 我在浏览器上看的,到了 35 页豆瓣电影科幻分类就没有电影了,不知道是不是科幻电影就这么多?
    quietin
        29
    quietin  
       2015-12-25 17:05:03 +08:00
    @luohaha 明显不是,自己思考吧
    luohaha
        30
    luohaha  
    OP
       2015-12-25 17:11:15 +08:00
    @quietin 大神求教,我在浏览器上也看不到啊!
    luohaha
        31
    luohaha  
    OP
       2015-12-25 17:16:29 +08:00
    @quietin 我觉得就是只有这么多,至少从这个入口进去只有这么多~
    luohaha
        32
    luohaha  
    OP
       2015-12-25 17:29:27 +08:00
    @quietin 我在豆瓣选电影的页面,选科幻后,一直点击加载更多,最后也是只有这么多部~
    Killian
        33
    Killian  
       2015-12-25 18:08:10 +08:00
    一般网站会做 大页数 翻页请求优化 比如只返回你 35 的数据 因为这种查询性能很低
    luohaha
        34
    luohaha  
    OP
       2015-12-25 19:19:09 +08:00
    @Killian 我作为一个正常用户,用浏览器访问豆瓣电影,翻到 35 页之后没有电影了,这是翻页请求优化?连用户都不用正常使用的优化。。
    kelos
        35
    kelos  
       2015-12-25 19:53:29 +08:00
    像一些 web 的通讯工作之类的,你们都可以抓?
    geekboy
        36
    geekboy  
       2015-12-25 20:00:04 +08:00
    前几天用 java 在抓,现在豆瓣 apikey 不让申请了,我也遇到过几次 403~
    quietin
        37
    quietin  
       2015-12-25 21:32:43 +08:00
    @luohaha 忘了多谢你给我科普抓取过程和布隆过滤器了
    luohaha
        38
    luohaha  
    OP
       2015-12-25 21:51:18 +08:00
    @geekboy 是吗?之前还申请过 douban 的 apikey 来做过一个应用。
    luohaha
        39
    luohaha  
    OP
       2015-12-25 21:52:22 +08:00
    @kelos 什么意思?就是正常的爬虫抓取啊。
    njutree
        40
    njutree  
       2015-12-25 22:02:32 +08:00
    @luohaha 正常用户翻到 35 页也说明了用户的搜索不准确,用户应该做的是使用更准确的词再搜索才是更好的方式。不然除了给爬虫的人有便利其实意义不大,而且做过后端的人都知道分布式分页的问题。
    luohaha
        41
    luohaha  
    OP
       2015-12-25 22:23:56 +08:00
    @njutree 好吧确实没有遇见过这么判别爬虫的。。一般都是根据抓取间隔, ip 等。。不过我无聊的时候会在一个分类下,一页一页地翻找电影看,如果真是你说的这样,看来以前我都是被豆瓣当成爬虫了。。
    luohaha
        42
    luohaha  
    OP
       2015-12-25 22:27:12 +08:00
    @njutree 你在做后端的时候会这么过滤爬虫吗?能给推荐一下一些这方面的博客吗?
    decaywood
        43
    decaywood  
       2015-12-25 22:38:34 +08:00
    cookie 写死了,你得引入 cookie 过期重新获取功能,不然有点废
    luohaha
        44
    luohaha  
    OP
       2015-12-25 22:43:04 +08:00
    @decaywood 嗯嗯,会改进的,多谢啦
    decaywood
        45
    decaywood  
       2015-12-25 22:46:30 +08:00
    java 版的股票爬虫也写过一个, https://github.com/decaywood/XueQiuSuperSpider ,爬虫这东西个人认为,可以根据抓取数据的生命周期划分一下模块,每个模块提供相应的可拔插机制,方便程序进行技术迭代,可以有效提高程序的生命力、
    luohaha
        46
    luohaha  
    OP
       2015-12-25 22:49:59 +08:00
    @decaywood Thanks!
    lx19930805
        47
    lx19930805  
       2015-12-26 10:34:07 +08:00
    我比较好奇的是楼上说的,一般人只能看到几页,后面更多的看不到了.
    对于刚接触的我来说,我比较想知道如何获取更多.

    不过我发现一个问题?为什么我直接改后面的页数回车后不能直接跳到指定页数,而是刷新第一页呢?
    njutree
        48
    njutree  
       2015-12-26 21:47:54 +08:00
    @luohaha 我觉得你没有看懂我在说啥,本质并不是为了屏蔽爬虫。
    luohaha
        49
    luohaha  
    OP
       2015-12-26 21:58:05 +08:00
    @njutree 的确,我后面才理解了。。
    angryRabbit
        50
    angryRabbit  
       2015-12-26 22:35:27 +08:00
    就想问一下,楼主写单元测试了吗?
    luohaha
        51
    luohaha  
    OP
       2015-12-26 22:41:12 +08:00
    @angryRabbit 写了,不过我习惯最后删掉。。
    luohaha
        52
    luohaha  
    OP
       2015-12-26 22:43:17 +08:00
    @angryRabbit 我想象不出不写测试单元,如何开发稍大点的程序
    kelos
        53
    kelos  
       2015-12-27 18:35:57 +08:00
    @luohaha 你看看阿里的 web 版钉钉,抓包根本就没有信息,这样的工具,联系人信息,能抓出来?
    wizardforcel
        54
    wizardforcel  
       2016-01-01 18:32:21 +08:00
    为啥不用 go 写

    go 就是没有分号的 c 语言

    并且处理字符串还方便一些
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2839 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 15:06 · PVG 23:06 · LAX 08:06 · JFK 11:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.