赞
踩
首先这种网站一定要设置爬取的速率,目标网站用这种方式写入网页估计是被爬虫搞怕了,大概率有更简单的反爬方法,因此爬取速率要注意。博主要爬的网站是一个电影网站:艺恩,点击下一页可以看到其实执行了一个js拿数据,但是URL却没有任何变化,我们需要一路下一页下一页点下去,然后把展示出的电影详情也搞到。
爬取思路:
# -*- coding: gbk -*- from scrapy.spiders import CrawlSpider import scrapy from urllib.parse import urljoin class MovieDetailSpider(CrawlSpider): name = "flim" allowed_domains = ["endata.com.cn"] def start_requests(self): start_url = 'https://www.endata.com.cn/BoxOffice/MovieStock/movies.html' self.page = 1 # 当前主页的页面 self.max_page = 500 # 预期爬取的最大页面,这个可以往大调整,目的是及时退出循环。 yield scrapy.Request(start_url, self.parse, dont_filter=True, meta={ 'page': self.page, }) def parse(self, response): # 这里是拿到详情页后的函数 # 1. 提取出这个页面中出现的电影,然后传给movie_detail_page方法提取电影详情页的内容 li_movie_list = response.css('ul.movies-list-box li') for li_movie_info in li_movie_list[:2]: relative_url = li_movie_info.css('a::attr(href)').extract_first() relative_url = relative_url.strip() movie_url = urljoin(response.url, relative_url) yield scrapy.Request(movie_url, callback=self.movie_detail_page, dont_filter=False) # when you run, turn to True # 重要!这是个 死循环/递归 操作,把详情页的URL继续发送给middleware,回调自己,以方便再次从页面中提取电影列表 start_url = 'https://www.endata.com.cn/BoxOffice/MovieStock/movies.html' self.page += 1 if self.page < self.max_page: yield scrapy.Request(start_url, self.parse, dont_filter=True, meta={ 'page': self.page, }) # next page begin def movie_detail_page(self, response): movie_dict = {} # 这是个提取电影详情页的函数,提取出来内容yield给pipeline保存就行 yield movie_dict
class HandlessMiddleware(object): def __init__(self): # 在构造方法里创建Chrome窗口与两个标签页 super(HandlessMiddleware, self).__init__() option = webdriver.ChromeOptions() option.add_argument('headless') prefs = { "profile.managed_default_content_settings.images": 2, # 禁止加载图片 'permissions.default.stylesheet': 2, # 禁止加载css } option.add_experimental_option("prefs", prefs) self.browser = webdriver.Chrome(chrome_options=option) self.browser.implicitly_wait(5) self.browser.execute_script('window.open("","_blank");') # 新建一个标签页 # 每个URL都会被送到这里,所以要根据不同的url判断 # 1. 定位到哪一个标签页 # 2. 是抓取传来的URL还是点击下一页 def process_request(self, request, spider): # 如果是首页url,意味着要点击“下一页” if request.url == 'https://www.endata.com.cn/BoxOffice/MovieStock/movies.html': # 如果是第一次爬取,那么需要把首页抓下来 if request.meta['page'] == 1: self.browser.switch_to.window(self.browser.window_handles[0]) self.browser.get(request.url) self.max_page = int(self.browser.find_element_by_id('TableList_Paging').find_element_by_css_selector( 'a.layui-laypage-last').text) # 这个是首页分了多少页,也就是要点多少次“下一页” else: # 如果不是第一次遇到首页url,意味着不需要抓取这个url,而是点击“下一页” self.browser.switch_to.window(self.browser.window_handles[0]) if request.meta['page'] <= self.max_page: print("MAIN PAGE CHANGE : " + str(request.meta['page']) + " / " + str(self.max_page)) self.browser.find_element_by_id('TableList_Paging').find_element_by_class_name( 'layui-laypage-next').click() # get next page else: return None else: # 这是遇到了电影详情页的url,切换到第2个标签页然后得到详情页内容,传回去,传给哪个函数是由第一个文件spider里callback指定的,middleware只需要不择手段拿到网页内容即可。 print("NEW PAGE GET : " + request.url) self.browser.switch_to.window(self.browser.window_handles[1]) self.browser.get(request.url) time.sleep(2) return HtmlResponse(url=self.browser.current_url, body=self.browser.page_source, encoding="utf-8",request=request)
ROBOTSTXT_OBEY = False
COOKIES_ENABLED = False
DOWNLOADER_MIDDLEWARES = {
'scrapy.downloadermiddlewares.useragent.UsserAgentMiddleware': None,
'movie_data.middlewares.HandlessMiddleware': 200,
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。