公众号原文

创建数据库

我在上一篇笔记中已经创建了数据库,具体查看《scrapy电影天堂实战(一)创建数据库》,这篇笔记创建scrapy实例,先熟悉下要用到到xpath知识

用到的xpath相关知识

reference: https://germey.gitbooks.io/python3webspider/content/4.1-XPath的使用.html

  1. nodename 选取此节点的所有子节点
  2. / 从当前节点选取直接子节点
  3. // 从当前节点选取子孙节点
  4. . 选取当前节点
  5. .. 选取当前节点的父节点
  6. @ 选取属性

//title[@lang='eng'],

这就是一个 XPath 规则,它就代表选择所有名称为 title,同时属性 lang 的值为 eng 的节点。

  • 属性多值匹配
  1. from lxml import etree
  2. text = '''
  3. <li class="li li-first"><a href="link.html">first item</a></li>
  4. '''
  5. html = etree.HTML(text)
  6. result = html.xpath('//li[@class="li"]/a/text()')
  7. print(result)

在这里 HTML 文本中的 li 节点的 class 属性有两个值 li 和 li-first,但是此时如果我们还想用之前的属性匹配获取就无法匹配了, 如果属性有多个值就需要用 contains() 函数了

  1. result = html.xpath('//li[contains(@class, "li")]/a/text()')
  • 多属性匹配
  1. from lxml import etree
  2. text = '''
  3. <li class="li li-first" name="item"><a href="link.html">first item</a></li>
  4. '''
  5. html = etree.HTML(text)
  6. result = html.xpath('//li[contains(@class, "li") and @name="item"]/a/text()')
  7. print(result)

在这里 HTML 文本的 li 节点又增加了一个属性 name,这时候我们需要同时根据 class 和 name 属性来选择,就可以 and 运算符连接两个条件,两个条件都被中括号包围。

  • 按序选择
  1. result = html.xpath('//li[position()<3]/a/text()')
  2. result = html.xpath('//li[last()-2]/a/text()')

scrapy-python3的dockerfile(可忽略)

可用该dockerfile自行构建镜像

  1. FROM ubuntu:latest
  2. MAINTAINER vickeywu <vickeywu557@gmail.com>
  3. RUN apt-get update
  4. RUN apt-get install -y python3.6 python3-pip python3-dev && \
  5. ln -snf /usr/bin/python3.6 /usr/bin/python
  6. RUN apt-get clean && \
  7. rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/* /tmp/* /var/tmp/*
  8. RUN pip3 install --upgrade pip && \
  9. ln -snf /usr/local/bin/pip3.6 /usr/bin/pip && \
  10. pip install --upgrade scrapy && \
  11. pip install --upgrade pymysql && \
  12. pip install --upgrade redis && \
  13. pip install --upgrade bitarray && \
  14. pip install --upgrade mmh3
  15. WORKDIR /home/scrapy_project
  16. CMD touch /var/log/scrapy.log && tail -f /var/log/scrapy.log

python2环境设置编码使用utf8 (使用python3环境可忽略)

  • set var in settings.py
  1. PAGE_ENCODING = 'utf8'
  • quote in other file.py:
  1. from scrapy.utils.project import get_project_settings
  2. settings = get_project_settings()
  3. PAGE_ENCODING = settings.get('PAGE_ENCODING')
  • set utf8 directly
  1. sys.setdefaultencoding('utf8')
  2. body = (response.body).decode('utf8','ignore')
  3. body = str((response.body).decode('utf16','ignore')).encode('utf8')

创建爬虫

现在正式创建scrapy实例

  1. root@ubuntu:/home/vickey# docker pull vickeywu/scrapy-python3
  2. root@ubuntu:/home/vickey# mkdir scrapy_project # 创建个文件夹存放scrapy项目
  3. root@ubuntu:/home/vickey# cd scrapy_project/
  4. root@ubuntu:/home/vickey/scrapy_project# docker run -itd --name scrapy_movie -v /home/vickey/scrapy_project/:/home/scrapy_project/ vickeywu/scrapy-python3 # 使用已构建好的镜像创建容器
  5. 84ae2ee9f02268c68e59cabaf3040d8a8d67c1b2d1442a66e16d4e3e4563d8b8
  6. root@ubuntu:/home/vickey/scrapy_project# docker ps
  7. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  8. 84ae2ee9f022 vickeywu/scrapy-python3 "scrapy shell --nolog" 3 seconds ago Up 2 seconds scrapy_movie
  9. d8afb121afc6 mysql "docker-entrypoint.s…" 4 days ago Up 3 hours 33060/tcp, 0.0.0.0:8886->3306/tcp scrapy_mysql
  10. root@ubuntu:/home/vickey/scrapy_project# docker exec -it scrapy_movie /bin/bash
  11. root@84ae2ee9f022:/home/scrapy_project# ls # 挂载的目录暂时没有任何东西,等下创建了项目便会将文件挂载到宿主机,方便修改
  12. root@84ae2ee9f022:/home/scrapy_project# scrapy --help # 查看帮助命令

  13. root@84ae2ee9f022:/home/scrapy_project# scrapy startproject movie_heaven_bar # 创建项目名为movie_heaven_bar
  14. New Scrapy project 'movie_heaven_bar', using template directory '/usr/local/lib/python3.6/dist-packages/scrapy/templates/project', created in:
  15. /home/scrapy_project/movie_heaven_bar
  16. You can start your first spider with:
  17. cd movie_heaven_bar
  18. scrapy genspider example example.com
  19. root@84ae2ee9f022:/home/scrapy_project# ls
  20. movie_heaven_bar
  21. root@84ae2ee9f022:/home/scrapy_project# cd movie_heaven_bar/ # 进入项目后再创建爬虫
  22. root@84ae2ee9f022:/home/scrapy_project/movie_heaven_bar# ls
  23. movie_heaven_bar scrapy.cfg
  24. root@84ae2ee9f022:/home/scrapy_project/movie_heaven_bar# scrapy genspider movie_heaven_bar www.dytt8.net # 创建爬虫名为movie_heaven_bar失败,不能与项目同名。。改个名
  25. Cannot create a spider with the same name as your project
  26. root@84ae2ee9f022:/home/scrapy_project/movie_heaven_bar# scrapy genspider newest_movie www.dytt8.net # 创建爬虫名为newest_movie
  27. Created spider 'newest_movie' using template 'basic' in module:
  28. movie_heaven_bar.spiders.newest_movie
  29. root@84ae2ee9f022:/home/scrapy_project/movie_heaven_bar# cd movie_heaven_bar/
  30. root@84ae2ee9f022:/home/scrapy_project/movie_heaven_bar/movie_heaven_bar# ls
  31. __init__.py __pycache__ items.py middlewares.py pipelines.py settings.py spiders
  32. root@84ae2ee9f022:/home/scrapy_project/movie_heaven_bar/movie_heaven_bar# cd spiders/
  33. root@84ae2ee9f022:/home/scrapy_project/movie_heaven_bar/movie_heaven_bar/spiders# ls # 创建的爬虫文件会在项目的spiders文件夹下
  34. __init__.py __pycache__ newest_movie.py
  35. root@84ae2ee9f022:/home/scrapy_project/movie_heaven_bar/movie_heaven_bar/spiders# exit # 退出容器
  36. exit
  37. root@ubuntu:/home/vickey/scrapy_project# ls # 退出容器后可以看到创建的项目文件已经挂载到宿主机本地,接下来在宿主机撸代码即可
  38. movie_heaven_bar

撸代码

  • items.py
  1. # -*- coding: utf-8 -*-
  2. # Define here the models for your scraped items
  3. #
  4. # See documentation in:
  5. # https://doc.scrapy.org/en/latest/topics/items.html
  6. import scrapy
  7. from scrapy.item import Item, Field
  8. class MovieHeavenBarItem(scrapy.Item):
  9. # define the fields for your item here like:
  10. # name = scrapy.Field()
  11. #pass
  12. movie_link = Field()
  13. movie_name = Field()
  14. movie_director = Field()
  15. movie_actors = Field()
  16. movie_publish_date = Field()
  17. movie_score = Field()
  18. movie_download_link = Field()
  • settings.py

数据库设置、延时设置、启用pipeline、日志设置,暂时只用到这些

  1. BOT_NAME = 'movie_heaven_bar'
  2. SPIDER_MODULES = ['movie_heaven_bar.spiders']
  3. NEWSPIDER_MODULE = 'movie_heaven_bar.spiders'
  4. # db settings
  5. DB_SETTINGS = {
  6. 'DB_HOST': '192.168.229.128',
  7. 'DB_PORT': 8886,
  8. 'DB_DB': 'movie_heaven_bar',
  9. 'DB_USER': 'movie',
  10. 'DB_PASSWD': '123123',
  11. }
  12. # obey ROBOTS.txt set True if raise error set False
  13. ROBOTSTXT_OBEY = True
  14. # delay 3 seconds
  15. DOWNLOAD_DELAY = 3
  16. # enable pipeline
  17. ITEM_PIPELINES = {
  18. 'movie_heaven_bar.pipelines.MovieHeavenBarPipeline': 300,
  19. }
  20. # log settings
  21. LOG_LEVEL = 'INFO'
  22. LOG_FILE = '/var/log/scrapy.log'
  • pipelines.py

reference: https://docs.scrapy.org/en/latest/topics/item-pipeline.html?highlight=filter#item-pipeline

项目爬虫(scrapy genspider spidername命令生成到爬虫文件)抓取到数据之后将它们发送到项目管道(项目下到pipelines.py文件里定义到各种class),管道通过settings.py里面定义的ITEM_PIPELINES优先级顺序(0~1000从小到大)来处理数据。

作用:1.清洗数据 2.验证数据(检查项目是否包含某些字段) 3.检查重复项(并删除它们) 4.将数据存储到数据库

reference: http://scrapingauthority.com/scrapy-database-pipeline/

  1. # -*- coding: utf-8 -*-
  2. # Define your item pipelines here
  3. #
  4. # Don't forget to add your pipeline to the ITEM_PIPELINES setting
  5. # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
  6. import pymysql
  7. from scrapy.exceptions import NotConfigured
  8. class MovieHeavenBarPipeline(object):
  9. def __init__(self, host, port, db, user, passwd):
  10. self.host = host
  11. self.port = port
  12. self.db = db
  13. self.user = user
  14. self.passwd = passwd
  15. # reference: doc.scrapy.org/en/latest/topics/item-pipeline.html#from_crawler
  16. @classmethod
  17. def from_crawler(cls, crawler):
  18. db_settings = crawler.settings.getdict('DB_SETTINGS')
  19. if not db_settings:
  20. raise NotConfigured
  21. host = db_settings['DB_HOST']
  22. port = db_settings['DB_PORT']
  23. db = db_settings['DB_DB']
  24. user = db_settings['DB_USER']
  25. passwd = db_settings['DB_PASSWD']
  26. return cls(host, port, db, user, passwd)
  27. def open_spider(self, spider):
  28. self.conn = pymysql.connect(
  29. host=self.host,
  30. port=self.port,
  31. db=self.db,
  32. user=self.user,
  33. passwd=self.passwd,
  34. charset='utf8',
  35. use_unicode=True,
  36. )
  37. self.cursor = self.conn.cursor()
  38. def process_item(self, item, spider):
  39. sql = 'INSERT INTO newest_movie(movie_link, movie_name, movie_director, movie_actors, movie_publish_date, movie_score, movie_download_link) VALUES (%s, %s, %s, %s, %s, %s, %s)'
  40. self.cursor.execute(sql, (item.get('movie_link'), item.get('movie_name'), item.get('movie_director'), item.get('movie_actors'), item.get('movie_publish_date'), item.get('movie_score'), item.get('movie_download_link')))
  41. self.conn.commit()
  42. return item
  43. def close_spider(self, spider):
  44. self.conn.close()
  • spiders/newest_movie.py
  1. # -*- coding: utf-8 -*-
  2. import scrapy
  3. import time
  4. import logging
  5. from scrapy.http import Request
  6. from movie_heaven_bar.items import MovieHeavenBarItem
  7. class NewestMovieSpider(scrapy.Spider):
  8. name = 'newest_movie'
  9. allowed_domains = ['www.dytt8.net']
  10. #start_urls = ['http://www.dytt8.net/']
  11. # 从该urls列表开始爬取
  12. start_urls = ['http://www.dytt8.net/html/gndy/dyzz/']
  13. def parse(self, response):
  14. item = MovieHeavenBarItem()
  15. domain = "https://www.dytt8.net"
  16. urls = response.xpath('//b/a/@href').extract() # list type
  17. #print('urls', urls)
  18. for url in urls:
  19. url = domain + url
  20. yield Request(url=url, callback=self.parse_single_page, meta={'item': item}, dont_filter = False)
  21. # 爬取下一页
  22. last_page_num = response.xpath('//select[@name="sldd"]//option[last()]/text()').extract()[0]
  23. last_page_url = 'list_23_' + last_page_num + '.html'
  24. next_page_url = response.xpath('//div[@class="x"]//a[last() - 1]/@href').extract()[0]
  25. if next_page_url != last_page_url:
  26. url = 'https://www.dytt8.net/html/gndy/dyzz/' + next_page_url
  27. logging.log(logging.INFO, '***************** page num ***************** ')
  28. logging.log(logging.INFO, 'crawling page: ' + next_page_url)
  29. yield Request(url=url, callback=self.parse, meta={'item': item}, dont_filter = False)
  30. def parse_single_page(self, response):
  31. item = response.meta['item']
  32. item['movie_link'] = response.url
  33. detail_row = response.xpath('//*[@id="Zoom"]//p/text()').extract() # str type list
  34. # 将网页提取的str列表类型数据转成一个长字符串, 以圆圈为分隔符,精确提取各个字段具体内容
  35. detail_list = ''.join(detail_row).split('◎')
  36. logging.log(logging.INFO, '******************log movie detail*******************')
  37. item['movie_name'] = detail_list[1][5:].replace(6*u'\u3000', u', ')
  38. logging.log(logging.INFO, 'movie_link: ' + item['movie_link'])
  39. logging.log(logging.INFO, 'movie_name: ' + item['movie_name'])
  40. # 找到包含特定字符到字段
  41. for field in detail_list:
  42. if '主\u3000\u3000演' in field:
  43. # 将字段包含杂质去掉[5:].replace(6*u'\u3000', u', ')
  44. item['movie_actors'] = field[5:].replace(6*u'\u3000', u', ')
  45. logging.log(logging.INFO, 'movie_actors: ' + item['movie_actors'])
  46. if '导\u3000\u3000演' in field:
  47. item['movie_director'] = field[5:].replace(6*u'\u3000', u', ')
  48. logging.log(logging.INFO, 'movie_directors: ' + item['movie_director'])
  49. if '上映日期' in field:
  50. item['movie_publish_date'] = field[5:].replace(6*u'\u3000', u', ')
  51. logging.log(logging.INFO, 'movie_publish_date: ' + item['movie_publish_date'])
  52. if '豆瓣评分' in field:
  53. item['movie_score'] = field[5:].replace(6*u'\u3000', u', ')
  54. logging.log(logging.INFO, 'movie_score: ' + item['movie_score'])
  55. # 此处获取的是迅雷磁力链接,安装好迅雷,复制该链接到浏览器地址栏迅雷会自动打开下载链接,个别网页结构不一致会获取不到链接
  56. try:
  57. item['movie_download_link'] = ''.join(response.xpath('//p/a/@href').extract())
  58. logging.log(logging.INFO, 'movie_download_link: ' + item['movie_download_link'])
  59. except Exception as e:
  60. item['movie_download_link'] = response.url
  61. logging.log(logging.WARNING, e)
  62. yield item

启动爬虫

  1. root@ubuntu:/home/vickey/scrapy_project/movie_heaven_bar# docker exec -it scrapy_movie /bin/bash
  2. root@1040aa3b7363:/home/scrapy_project# ls
  3. movie_heaven_bar
  4. root@1040aa3b7363:/home/scrapy_project# cd movie_heaven_bar/
  5. root@1040aa3b7363:/home/scrapy_project/movie_heaven_bar# ls
  6. movie_heaven_bar run.sh scrapy.cfg
  7. root@1040aa3b7363:/home/scrapy_project/movie_heaven_bar# sh run.sh & # 后台运行脚本,日志输出可以在/var/log/scrapy.log中看到
  8. root@1040aa3b7363:/home/scrapy_project/movie_heaven_bar# exit
  9. exit
  10. root@ubuntu:/home/vickey/scrapy_project/movie_heaven_bar# ls
  11. movie_heaven_bar README.md run.sh scrapy.cfg
  12. root@ubuntu:/home/vickey/scrapy_project/movie_heaven_bar# docker logs -f scrapy_movie # 使用docker logs -f --tail 20 scrapy_movie也可以看到scrapy的日志输出。
  • scrapy爬虫日志截图

  • scrapy数据库截图

结语

大功告成,现在我想看哪部电影只需要将movie_download_link链接复制到浏览器打开,即可自动打开迅雷链接下载电影了(前提是已经安装迅雷),然后就可以在迅雷边下边看了,美滋滋

不过,如果我中途停止了爬取,又要从头开始爬,所以就会有数据重复,很烦。下一篇笔记写下scrapy的去重方法,这样就不会有数据重复了,也可以节省爬取耗时。

代码已上传至github: https://github.com/Vickey-Wu/movie_heaven_bar

scrapy电影天堂实战(二)创建爬虫项目的更多相关文章

  1. scrapy电影天堂实战(一)创建数据库

    原文链接 这里的排版没微信公众号那么友好,建议查看公众号原文 创建数据库 首先我们需要创建数据库和表等来存储数据 创建mysql.cnf配置文件 oot@ubuntu:/mnt/test_scrapy ...

  2. 使用scrapy 创建爬虫项目

    使用scrapy 创建爬虫项目 步骤一: scrapy startproject tutorial 步骤二: you can start your first spider with: cd tuto ...

  3. Scrapy创建爬虫项目

    1.打开cmd命令行工具,输入scrapy startproject 项目名称 2.使用pycharm打开项目,查看项目目录 3.创建爬虫,打开CMD,cd命令进入到爬虫项目文件夹,输入scrapy ...

  4. ancconda创建爬虫项目

    # 安装 conda env list conda create -n <envname> conda activate <envname> conda install scr ...

  5. IOS开发实战-Xcode创建HelloWorld项目

    一.创建工程打开Xcode开发工具,在Welcome界面选择”Create a new Xcode project”选项 在选择模板窗口,选择”Single View Application” 确定模 ...

  6. 如何利用scrapy新建爬虫项目

    抓取豆瓣top250电影数据,并将数据保存为csv.json和存储到monogo数据库中,目标站点:https://movie.douban.com/top250 一.新建项目 打开cmd命令窗口,输 ...

  7. scrapy_电影天堂多页数据和图片下载

    嵌套的 爬取 先获取第一页的标题 点击标题到第二页的图片url 1.创建项目 > scrapy startproject scrapy_movie_099 2.创建爬虫文件 spiders> ...

  8. LINUX下安装搭建nodejs及创建nodejs-express-mongoose项目

    在Ubuntu中按CTRL+ALT+T打开命令窗口,按下面步骤和命令进行安装即可.添加sublime text 3的仓库.1.sudo add-apt-repository ppa:webupd8te ...

  9. Scrapy项目 - 源码工程 - 实现豆瓣 Top250 电影信息爬取的爬虫设计

    一.项目目录结构 spiders文件夹内包含doubanSpider.py文件,对于项目的构建以及结构逻辑,详见环境搭建篇. 二.项目源码 1.doubanSpider.py # -*- coding ...

随机推荐

  1. 2019春第十一周作业Compile Summarize

    这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 这里 我在这个课程的目标是 能按自己的想法解出题目 这个作业在那个具体方面帮助我实现目标 能朝着软件工程师方向发展 参考文献与网址 C语言 ...

  2. <每日一题> Day7:CodeForces-1166C.A Tale of Two Lands (二分 + 排序)

    原题链接 参考代码: #include <cstdio> #define mid ((l + r) / 2) #include <algorithm> using namesp ...

  3. POJ-2456.Aggressivecows.(二分求解最大化最小值)

    本题大意:在坐标轴上有n个点,现在打算在这n个点上建立c个牛棚,由于牛对厂主的分配方式表示很不满意,它很暴躁,所以它会攻击离它很近的牛来获得快感,这件事让厂主大大知道了,他怎么可能容忍?所以他决定有策 ...

  4. 牛客小白月赛16 A 小石的签到题 ( 博弈)

    链接:https://ac.nowcoder.com/acm/contest/949/A来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言52428 ...

  5. P3452 [POI2007]BIU-Offices

    传送门 首先能想到 $n^2$ 的做法 枚举所有两点,看看是否有边相连,如果没有说明它们一定要在同一集合,用并查集维护一下就行 注意到如果没有边这个条件,其实就相当于问补图有边 所以题意可以转化为,求 ...

  6. 【推荐系统】知乎live入门3.召回

    参考链接 [推荐系统]知乎live入门 目录 1. 概述 2. 画像过滤 3. 协同过滤 4. 内容过滤 5. 模型过滤 6. 其他过滤 7. 总结 ========================= ...

  7. installsheild2011打包程序internal build error 6213

    今天打包一个安装程序,总是出现报错,internal build error -6213,然后搜遍都没有找到什么解决方案.看到一个帖子,说是因为installsheild里面的build的时候自动扫描 ...

  8. JavaScript ES6 Promise对象

    说明 Node.js中,以异步(Async)回调著称,使用了异步,提高了程序的执行效率,但是,代码可读性较差的. 假如有几个异步操作,后一个操作需要前一个操作的执行完毕之后返回的数据才能执行下去,如果 ...

  9. vue+element ui 滚动加载

    <div id="app"> <div class="infinite-list-wrapper" style="overflow: ...

  10. bzoj5084 hashit 广义SAM+树链的并

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5084 题解 考虑平常对于静态问题,我们应该如何用 SAM 求本质不同的子串个数. 对于一个常规 ...