# 按照我个人的习惯,在一些需要较多的包作为基础支撑的项目里,习惯使用虚拟环境,因为这样能极大程度的减少出现依赖冲突的问题。依赖冲突就比如A、B、C三个库,A和B同时依赖于C,但是A需要的C库版本大于N,而B库在C库版本大于N时会有依赖错误。如果是在同一个项目里三者都需要,那么我们必然要想办法解决,但是如果是在不同项目里,但是使用同一环境所引起的,那么只需要使用不同环境即可,能省去不少时间和精力。
一、新建项目
(一)新建python项目并创建虚拟环境
使用pycharm (社区版即可),新建一个项目,解释器就选新建虚拟环境。等待python解释器制作好虚拟环境后,在界面左下角找到终端,点击进入新建好的虚拟环境。
如果进入失败的话直接在终端找到该文件夹,进入到进入到当前创建虚拟目录的\env_demo\Scripts下,使用命令activate激活虚拟环境。
无论你是如何进入的终端,在命令行的最前面只要出现了虚拟环境名称,例如
(.venv) D:\pythonProject\scrapy\myscrapy>
那么就证明虚拟环境创建成功。
(二)安装scrapy库并新建一个scrapy项目
使用pip命令安装scrapy
pip install scrapy
在安装过程中可以看到安装了众多的依赖包,这就是为什么要使用虚拟环境的主要原因了——易于管理。
使用startproject新建scrapy项目,例如项目就叫douban
scrapy startproject douban
执行之后应该会提示两个命令,依次执行即可。
cd douban
scrapy genspider example example.com
scrapy genspider example example.com中example和example.com写哈
例如本次案例,就是scrapy genspider scrapydouban https://movie.douban.com/top250
新建完成之后就可以看到如下项目结构。
二、完善项目
(一)准备工作
打开scrapydouban.py,代码如下。
import scrapyclass ScrapydoubanSpider(scrapy.Spider):name = "scrapydouban"allowed_domains = ["movie.douban.com"]start_urls = ["https://movie.douban.com/top250"]def parse(self, response):pass
name 就是我们的scrapy项目名字,这里改的话要到setting等文件里也要改哟!因为豆瓣250的请求网址的参数是每次递增25,所以我们需要重写一下start_requests,还有就是parse函数可能会报一个警告,需要加一个参数。重写之后的代码如下。
import scrapy
from scrapy import Request
from typing import Iterable
class ScrapydoubanSpider(scrapy.Spider):name = "scrapydouban"allowed_domains = ["movie.douban.com"]start_urls = ["https://movie.douban.com/top250"]def start_requests(self) -> Iterable[Request]:for i in range(10):url = f'https://movie.douban.com/top250?start={i * 25}&filter='yield scrapy.Request(url=url, callback=self.parse)def parse(self, response, **kwargs):pass
注意在start-requests中必须要有一个yield一下,将网址返回给引擎。
在parse中,response就是返回的response对象,初学时我们主要工作就是在这里。
(二)目标网页Xpath提取目标元素
首先定位到包含一整页的包含所有信息的li标签组成的集合。选中的xpath为
//*[@id="content"]/div/div[1]/ol//li
我们选取四个字段进行提取,标题、导演等信息文本、评分、评价人数和短评,提取相当于上述所提取的每个li的xpath。
出于规范管理,我们还可以在item文件里定义一下我们的字段,并且在scrapydouban中引用。
import scrapyclass DoubanItem(scrapy.Item):title = scrapy.Field()text = scrapy.Field()rating = scrapy.Field()review = scrapy.Field()quote = scrapy.Field()
完善后的parse函数如下。
def parse(self, response, **kwargs):lis = response.xpath('//*[@id="content"]/div/div[1]/ol//li') # 获取所有li标签for i in lis:item = DoubanItem()item['title'] = i.xpath('./div/div[2]/div[1]/a/span[1]/text()').extract_first() # 标题item['text'] = i.xpath('./div/div[2]/div[2]/p[1]/text()[1]').extract_first().replace('\n','').strip().replace(' ', '') # 文本item['rating'] = i.xpath('./div/div[2]/div[2]/div/span[2]/text()').extract_first() # 评分item['review'] = i.xpath('./div/div[2]/div[2]/div/span[4]/text()').extract_first() # 评价人数item['quote'] = i.xpath('./div/div[2]/div[2]/p[2]/span[1]/text()').extract_first() # 短评print(item)yield item
三、运行项目
使用命令运行该项目
scrapy crawl scrapydouban
在终端就会输出很多的日志信息,但是我们希望的元素信息并没有打印出来。仔细看看日志信息。
响应是403,为什么?好像忘了加请求头了,那不就明摆着告诉目标服务器我是一个爬虫程序嘛,所以需要在setting.py中打开头部信息。
默认头部信息,建议完善更改
DEFAULT_REQUEST_HEADERS = {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Accept-Language": "en",
}
再次使用命令启动项目
到此我们就已经可以得到目标元素了。后续章节还会介绍其他组件,包括中间件,数据库入库,js逆向调用等。