Scpapy 总体流程原理
教科书式解释
代码写好,程序开始运行
1 、引擎:Hi,Spider,你要处理哪个网站?
2 、Spider:老大要我处理xxx.com。
3 、引擎:你把第一个需要处理的URL给我吧。
4 、Spider:给你,第一个URL是xxx.com。
5 、引擎:HI!调度器,王这有request请求你帮我排序入队一下。
6 、调度器:好的,正在处理你等一下。
7、 引擎:HI!调度器,把你处理好的request请求给我。
8 、调度器:给你,这是我处理好的request。
9 、引擎:hi!下载器,你按照老大的下载中间件的设置帮我下载一下这个request请求。
10 、下载器:好的!给你,这是下载好的东西。(如果失败:sorry,这个request下载失败了。然后引擎告诉调度器,这个request下载失败了,你记录以下,我们待会儿再下载)
11 、引擎:hi!Spider,这是下载好的东西,并且已经按照老大的下载中间件处理好了,你自己处理一下(注意!这儿responses默认是交给def parse()这个函数处理的)
12 、Spider:(处理完毕数据之后对需要跟进的URL),HI,引擎,王这里有两个结果,这个是我需要跟进的URL,还有这个是我获取到的item数据。
13 、引擎:hi!管道,王这儿有个item你帮我处理一下!调度器!这是需要跟进的URL你帮我处理下,然后从第四步开始循环,直到获取完老大需要的全部信息。
14 、管道‘’调度器:好的,现在就做!
Scarpy 爬虫具体流程
-
scrapy startproject 项目名称
-
cd 项目名称
-
scrapy genscrapy 爬虫名 域名
- 启动爬虫
- –nolog取消日志
- scrapy crawl spider爬虫名 -o xxx.json #保存为JSON文件
scrapy crawl spider爬虫名 -o xxx.jl或jsonlines #每个Item输出一行json
scrapy crawl spider爬虫名 -o xxx.csv #保存为csv文件
scrapy crawl spider爬虫名 -o xxx.xml #保存为xml文件
-
进入spiders目录,首先确定需要爬取的目标?有几个目标?然后进入items.py文件添加Filed
- items.py 相当于一个映射文件,将爬取的数据变成items,scrapy.Field() 就好似字典作用
-
开始编写爬虫(有两个固定方法,parse和start_requests)
-
首先修改start_urls,它是第一个爬取的url(后面要是html或者/结尾)
-
编写parse方法,其中参数response是downloads传递过来的响应(方法参数很多)
-
response最常用的两个方法:response.xpath、response.urljoin
-
对于xpath获取到的数据我们需要使用:extract()、extract_first() 他们返回值都是str类型
-
对于多级页面爬取数据使用:yield scrapy.Request(url=url,callback=self.parse,meta={‘item’:item},cookie=‘xxx’, dont_filter=False) dont_filter是否过滤重复请求
-
对于模拟登录发送post请求我们一般使用: yield scrapy.FromRequest(url=xxx,callback=xxx,formdata=xxx)
-
翻页功能:yield scrapy.Request(url=url, callback=self.parse)
next_url = response.xpath('//div[@class="pageC"]/a[3]/@href').extract_first() if next_url: url = response.urljoin(next_url) yield scrapy.Request(url=url, callback=self.parse)
-
管道(pymysql 写入数据库)
- 三个固有方法:open_spider、process_item、close_spider(除process_item接收item外其他都只接收spider参数)
import pymysql # 注意之后需要去setting文件中开启管道 class XXXPipeline: def open_spider(self, spider): self.db = pymysql.connect( host='127.0.0.1', # 服务端地址 port=3306, # 服务端端口 user='root', # 用户名 password='', # 密码 database='', # 要连接的数据库 charset='utf8' # 设置数据库编码 ) self.cursor = self.db.cursor() def process_item(self, item, spider): sql = f'''insert into yzwmessage values(null,'{item['xxx']}','{item['xxx']}')''' # 执行sql语句 self.cursor.execute(sql) # 提交 self.db.commit() return item def close_spider(self, spider): self.cursor.close() self.db.close()
-
scrapy中间件的使用
1. scrapy中间件的分类和作用
1.1 scrapy中间件的分类
根据scrapy运行流程中所在位置不同分为:
- 下载中间件
- 爬虫中间件
1.2 scrapy中间的作用:预处理request和response对象
- 对header以及cookie进行更换和处理
- 使用代理ip等
- 对请求进行定制化操作,
但在scrapy默认的情况下 两种中间件都在middlewares.py一个文件中
爬虫中间件使用方法和下载中间件相同,且功能重复,通常使用下载中间件
2. 下载中间件的使用方法:
通过下载中间件来学习如何使用中间件 编写一个Downloader Middlewares和我们编写一个pipeline一样,定义一个类,然后在setting中开启
Downloader Middlewares默认的方法:
- process_request(self, request, spider):
- 当每个request通过下载中间件时,该方法被调用。
- 返回None值:没有return也是返回None,该request对象传递给下载器,或通过引擎传递给其他权重低的process_request方法
- 返回Response对象:不再请求,把response返回给引擎
- 返回Request对象:把request对象通过引擎交给调度器,此时将不通过其他权重低的process_request方法
- process_response(self, request, response, spider):
- 当下载器完成http请求,传递响应给引擎的时候调用
- 返回Resposne:通过引擎交给爬虫处理或交给权重更低的其他下载中间件的process_response方法
- 返回Request对象:通过引擎交给调取器继续请求,此时将不通过其他权重低的process_request方法
- 在settings.py中配置开启中间件,权重值越小越优先执行
Scapy+Selenium处理异步请求网站数据
-
重写下载器中间件的process_request或process_response方法
def process_request(self, request, spider): browser = spider.browser # 获取browser if request.url != self.newurl: # 判断是否变化了url,变化则更换网页 browser.get(request.url) self.newurl = request.url # js = "window.scrollTo({ top: 1200, behavior: 'smooth' });" # browser.execute_script(js) else: # 如果一直是请求相同url则只做点击事件,不更换网页 time.sleep(1) wait = WebDriverWait(browser, 5) wait.until(EC.presence_of_all_elements_located((By.XPATH, 'xxxxxxx'))) hoverable = browser.find_element(By.XPATH, 'xxxxx') webdriver.ActionChains(browser).move_to_element(hoverable).click().perform() time.sleep(1) return HtmlResponse(url=self.newurl, body=browser.page_source, request=request, encoding='utf8', status=200)
-
在spider下写一个__init__初始化函数 初始化browser
def __init__(self): super().__init__() chrome_options = webdriver.ChromeOptions() chrome_options.add_argument('--ignore-certificate-errors') chrome_options.add_argument('-ignore -ssl-errors') chrome_options.add_argument('--headless') # # 忽略无用的日志 # chrome_options.add_experimental_option("excludeSwitches", ['enable-automation', 'enable-logging']) self.browser = webdriver.Chrome(chrome_options=chrome_options)
-
其他一切与正常流程一样