01. 使用Scrapy实现数据爬取完整流程
1.1 创建新片场爬虫
1.1.1 创建并用PyCharm打开爬虫
创建一个名为XPCScrapy的工程。
(base) D:\Project\Python>scrapy startproject XPCScrapy New Scrapy project ‘XPCScrapy’, using template directory ‘C:\ProgramData\Anaconda3\lib\site-packages\scrapy\templates\project’, created in: D:\Project\Python\XPCScrapy
You can start your first spider with: cd XPCScrapy scrapy genspider example example.com
- 此时,Scrapy项目的根目录为:`D:\Project\Python\XPCScrapy`。
- 使用PyCharm打开Scrapy项目的根目录(D:\Project\Python\XPCScrapy)。
<a name="pAlz5"></a>
#### 1.1.2 配置settings文件
- 初始化settings.py文件,主要修改ROBOTSTXT_OBEY、DOWNLOAD_DELAY、DEFAULT_REQUEST_HEADERS三个字段的值。
```python
ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY = 1
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}
1.1.3 创建爬虫程序
创建新片场爬虫:
(base) D:\Project\Python\XPCScrapy>scrapy genspider xpc www.xinpianchang.com
Created spider 'xpc' using template 'basic' in module:
XPCScrapy.spiders.xpc
我们需要爬取的是广告页面中的内容,因此还需要将spiders/xpc.py文件中的XpcSpider类的start_urls属性改为新片场广告页面的地址。
class XpcSpider(scrapy.Spider):
name = 'xpc'
allowed_domains = ['www.xinpianchang.com']
start_urls = ['https://www.xinpianchang.com/discover/article-1-0-all-all-0-0-hot?from=navigator']
def parse(self, response):
pass
1.2 使用Scrapy提取数据
1.2.1 xpath()使用XPath提取数据
在
parse()
回调函数中的response
可以直接调用xpath()
函数来通过XPath提取数据。示例:提取广告页面的所有标题。
def parse(self, response):
for div in response.xpath('//*[@id="__next"]/section/main/div/div[3]/div'):
title = div.xpath('./div/div[2]/div[1]/a/h2/text()')
print(title)
编写完成后,可以通过
scrapy crawl xpc
来运行这个新片场爬虫。运行后,其中的一条数据为:
[<Selector xpath='./div/div[2]/div[1]/a/h2/text()' data='《同感》美的人感科技'>]
1.2.2 extract_first()/extract()/get()提取匹配数据
从1.2.1的运行结果中可以看出,XPath提取的结果格式为:
[<Selector xpath='XPath路径' data='提取到的数据'>]
。- 可以通过
extract_first()
/extract()
/get()
这三个函数提取data中的数据:extract_first()
:返回xpath()
结果中的第一项,并将其作为字符串返回。如果找不到匹配项,则返回None。extract()
:返回xpath()
查询结果中所有项,并以列表形式返回。如果未找到匹配项,则返回一个空列表。get()
:与extract_first()
类似,但是它只返回一个具体的值,而不是字符串或None。当匹配了多个元素时,只返回第一个匹配项的内容。
- 总的来说,
extract_first()
和extract()
适用于需要多次处理的xpath()
查询结果,而get()
通常用于只需要获取单个值的场景。 示例:获取广告页面的所有标题、对应的详情页链接、分类信息。
def parse(self, response):
for div in response.xpath('//*[@id="__next"]/section/main/div/div[3]/div'):
title = div.xpath('./div/div[2]/div/a/h2/text()').extract_first() # 标题
detail_page_url = div.xpath('./div/div[2]/div/a/@href').extract_first() # 详情页链接
category = div.xpath('./div/div[2]/div[2]/div/div/div/text()').extract_first() # 分类信息
print(title, detail_page_url, category)
1.2.3 在Scrapy中使用其他提取技术(以BeautifulSoup为例)
在Scrapy中要使用BeautifulSoup来提取数据,可以先通过
response.text
获取响应的源码,然后再用源码构建BS对象。- 构建完BS对象之后,所有的操作都与之前
requests + bs4
完全一致。 - 示例:利用BS4提取广告页面的所有标题、对应的详情页链接、分类信息。
```python
导入BeautifulSoup模块
from bs4 import BeautifulSoup
def parse(self, response):
# 构建BeautifulSoup对象
soup = BeautifulSoup(response.text, 'html.parser')
# 提取数据
for div in soup.select('main > div > div:nth-child(3) > div'):
title = div.select_one('div > div:nth-child(2) > div > a > h2').text # 标题
detail_page_url = div.select_one('div > div:nth-child(2) > div > a').attrs['href'] # 详情页链接
category = div.select_one('div > div:nth-child(2) > div:nth-child(2) > div > div').text # 分类信息
print(title, detail_page_url, category)
<a name="dlOML"></a>
### 1.3 封装Item
- Spiders中的数据提取完成后,会封装成Item。因此在正式存储数据之前,需要在items.py文件中编写Item。
- 自定义Item是一个继承自`scrapy.Item`类,Item属性的定义方式为:`属性名 = scrapy.Field()`。
- Item的结构由实际爬取的数据结构决定,如1.2中我们获取了title、detail_page_url、category三个字段的数据,这三个字段构成了广告的基本信息。
- 那么由此就可以在items.py文件中定义一个XpcBaseItem的类,然后在这个类中声明title、detail_page_url、category这三个属性。
```python
class XpcBaseItem(scrapy.Item):
title = scrapy.Field()
detail_page_url = scrapy.Field()
category = scrapy.Field()
修改回调函数中的内容。
def parse(self, response): for div in response.xpath(‘//*[@id=”__next”]/section/main/div/div[3]/div’):
# 提取数据。
title = div.xpath('./div/div[2]/div/a/h2/text()').extract_first() # 标题
detail_page_url = div.xpath('./div/div[2]/div/a/@href').extract_first() # 详情页链接
category = div.xpath('./div/div[2]/div[2]/div/div/div/text()').extract_first() # 分类信息
# 构建一个Item,并向里面填充数据。
# 填充格式为:`Item变量[Item所拥有的字段] = 数据`
item = XpcBaseItem()
item['title'] = title
item['detail_page_url'] = detail_page_url
item['category'] = category
# Item分装完成后,利用yield关键字将Item还给引擎。
# 引擎接下去会将Item传递给Item Pipeline。
yield item
<a name="ON0nX"></a>
### 1.4 Pipeline数据存储
- Item封装完成后,会进入Item Pipeline进行数据清洗与验证,最后实现存储。
- 因此,在pipelines.py中,可以编写数据的清洗、验证与存储逻辑。
- Pipeline是一个普通的自定义类,但这个自定义类一定存在一个`process_item(self, item, spider)`函数。
- 这个函数有且仅有self、item、spider三个参数,并且最后会将item返回。
- Item的清洗、验证与存储逻辑就写在`process_item()`中。
```python
import csv
class XpcPipeline:
def process_item(self, item, spider):
with open('./advertisement.csv', 'a', encoding='utf-8', newline='') as file:
csv_writer = csv.writer(file)
csv_writer.writerow((
item.get('title'),
item.get('detail_page_url'),
item.get('category')
))
return item
在Pipeline定义完成后,需要在settings.py文件的
ITEM_PIPELINES
字典中注册Pipeline。- 若没有在
ITEM_PIPELINES
中注册Pipeline,则该Pipeline不会生效。 - 在
ITEM_PIPELINES
中注册Pipeline的格式:Pipeline的位置: 优先级
。ITEM_PIPELINES = {
'XPCSpider.pipelines.XpcPipeline': 300,
}
- 若没有在
当上述所有步骤完成后,一个最基本的爬虫程序(数据爬取、数据提取、数据存储)就完成了。
此时就可以通过
scrapy crawl xpc
来运行爬虫程序了。02. 新片场爬虫项目(多请求与多Item处理)(06. 使用Scrapy完成新片场爬取 05:17)
爬取新片场广告页面的数据
- 爬取多页数据:10页。
- 广告页面:详情页连接。
- 详情页:爬取广告的标题、点赞数、收藏数。
- 其他:电影的播放地址、评论数据。
-
03. Scrapy爬虫基本开发流程总结
创建工程:
scrapy startproject PROJECT_NAME
- settings.py文件的基本配置。
- 创建爬虫:需要进入到PROJECT_NAME路径中,执行
scrapy genspider SPIDER_NAME SPIDER_DOMAIN
命令。 - 编写爬虫(SPIDER_NAME.py):编写start_urls起始地址、编写下一个请求、编写数据提取。
- 在items.py文件中编写数据存储结构。
- 在pipelines.py文件的process_item中编写数据处理与存储逻辑,并去settings.py中注册pipelines。
- 启动爬虫:
scrapy crawl SPIDER_NAME
。