模拟登录
知乎需要登录才能进入。
所以,爬取知乎的第一步就是模拟登录,这里我们使用的是selenium模拟登录。
start_requests函数是scrapy中spider的入口,所以模拟登录应该放在这个函数中,我们重写start_requests函数:
def start_requests(self):
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
os.system('chcp 65001')
os.popen('chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\selenum\AutomationProfile"')
chrome_options = Options()
chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
browser = webdriver.Chrome(
executable_path='F:\BaiduNetdiskDownload\ArticleSpider\chromedriver.exe',
options=chrome_options)
browser.get("https://www.zhihu.com/signin")
browser.find_element_by_css_selector(".SignFlow-accountInput.Input-wrapper input").send_keys("用户名")
import time
time.sleep(3)
browser.find_element_by_css_selector(".SignFlow-password input").send_keys("密码")
browser.find_element_by_css_selector(
".Button.SignFlow-submitButton").click()
time.sleep(10)
Cookies = browser.get_cookies()
print("----",Cookies)
cookie_dict = {
}
for cookie in Cookies:
cookie_dict[cookie['name']] = cookie['value']
browser.close()
return [scrapy.Request(url=self.start_urls[0],dont_filter=True,headers=self.headers,cookies=cookie_dict)] #callback默认是parse函数
模拟登录后,获取cookies,并在settings.py中将COOKIES_ENABLED设为True,这样我们就只需要在第一次请求中加上cookies,后面的所有请求都会默认带上cookies
COOKIES_ENABLED = True
另外,记得携带请求头,不然会被知乎识别为爬虫。
爬取所有的问题
由于知乎没有提供所有问题的入口,所以我们采用的是深度优先的爬取算法
模拟登录后,我们在parse函数中解析所有的问题url
经过分析,我们发现问题url的格式为:https://www.zhihu.com/question/问题id
使用filter函数过滤掉非https开头的url,过滤后的url如果是/question/***格式, 就提交给下载器,如果不是,则进一步解析跟踪。
def parse(self, response):
'''
提取出html页面中所有的url 并跟踪这些url进一步爬取
如果提取的格式为/question/*** 就提交给下载器
'''
all_urls = response.xpath('//a/@href').extract()
all_urls = [parse.urljoin(response.url,url) for url in all_urls]
all_urls = filter(lambda x: True if x.startswith('https') else False,all_urls) #过滤掉非https开头的url
for url in all_urls:
match_obj = re.match('(.*zhihu.com/question/(\d+))(/|$).*',url)
if match_obj:
#如果url格式为question格式,则下载后解析页面
request_url = match_obj.group(1)
request_id = match_obj.group(2)
yield scrapy.Request(request_url,headers=self.headers,meta={
"zhihuid":request_id},callback=self.parse_question)