在学习使用scrapy进行爬虫练习项目过程中遇到了一些问题,这里记录学习过程以及遇到问题的解决方法
练习项目分为如下4个阶段:
阶段1:scrapy抓取博客文章列表信息,包括url链接、文章名称、阅读数,并在终端用print打印出来
阶段2:将抓取的信息保存成Json文件
阶段3:将抓取的信息保存到MySQL数据库
阶段4:scrapy结合selenium进行网站登录
阶段1:
目标:scrapy抓取博客文章列表信息,包括url链接、文章名称、阅读数,并在终端用print打印出来
这个阶段算是scrapy的入门,包括安装:pip install scrapy,然后创建scrapy项目:scrapy startproject scrapytest(项目名称),然后创建爬虫脚本:cd scrapytest;scrapy genspider article_list(爬虫脚本名称) csdn.com(爬取的网站),然后就可以开始写爬虫代码了,网上和书上有很多入门介绍,在抓取网页之前这些步骤,我都进行得还比较顺利。
写爬虫代码前,先要分析网页的元素,然后可以在scrapy shell命令行进行抓取实验(xpath或css方式),可以抓取后就可以开始编写爬虫代码了,scrapy框架主要是编写3个内容:爬虫脚本(名称自己定义)、Pipeline(处理或保存抓取的Item)、Item(定义抓取的字段)
首先定义抓取字段items.py,抓取文章的链接、标题、阅读数
import scrapy
class ScrapytestItem(scrapy.Item):
# define the fields for your item here like:
link = scrapy.Field()
title = scrapy.Field()
reads = scrapy.Field()
然后实现爬取核心代码,命名为articles_list.py,只抓取5页
# -*- coding: utf-8 -*-
import scrapy
from scrapytest.items import ScrapytestItem
class ArticleListSpider(scrapy.Spider):
name = 'articles_list'
def __init__(self):
self.allowed_domains = ['blog.csdn.net']
self.start_urls = ['http://blog.csdn.net/luanpeng825485697/article/list/']
self.index = 1
def parse(self, response):
if self.index > 5:
return
self.index += 1
article_lists = response.xpath('//div[@class="article-list"]/div[@class="article-item-box csdn-tracking-statistics"]')
#print(article_lists)
for article_item in article_lists:
item = ScrapytestItem()
item['link'] = article_item.xpath('./h4/a/@href').extract_first()
item['title'] = article_item.xpath('./h4/a/text()').extract()[-1].strip()
item['reads'] = article_item.xpath('./div/p/span[@class="read-num"]/span[@class="num"]/text()').extract_first()
yield item
yield scrapy.Request(url=self.start_urls[0] + str(self.index),callback=self.parse)
最后在pipelines.py中打印爬取的item
class ScrapytestPipeline(object):
def process_item(self, item, spider):
#简单打印
print("链接:",item['link'])
print("标题:",item['title'])
print("阅读:",item['reads'])
为了方便在pycharm中操作scrapy命令行,增加一个begin.py代码,这样直接运行begin.py,就能运行整个爬虫项目了
from scrapy import cmdline
cmdline.execute("scrapy crawl articles_list".split())
阶段2
目标:将抓取的信息保存成Json文件
这里只需修改pipelines.py中的内容
import json
class ScrapytestPipeline(object):
def __init__(self):
#初始化json文件
self.json_file = open("article.json",'wb+')
self.json_file.write('[\n'.encode("utf-8"))
def close_spider(self,spider):
#关闭json文件
self.json_file.close()
def process_item(self, item, spider):
#保存为json
text = json.dumps(dict(item),ensure_ascii=False) + "\n"
self.json_file.write(text.encode('utf-8'))
运行项目后看到json文件内容如下
阶段3
目标:将抓取的信息保存到MySQL数据库
也只需修改pipelines.py文件
import MySQLdb
class ScrapytestPipeline(object):
def __init__(self):
#初始化MySQL数据库连接
self.db = MySQLdb.connect("localhost","rmc","rmc","test1",charset='utf8')
self.cursor = self.db.cursor()
self.sql = """CREATE TABLE IF NOT EXISTS article_list(
id INT PRIMARY KEY auto_increment,
link VARCHAR(300) not NULL,
title VARCHAR(50) not NULL,
doread VARCHAR(10) not NULL);"""
self.cursor.execute(self.sql)
def close_spider(self,spider):
#关闭数据库连接
print("*****关闭数据库连接*******")
self.cursor.close()
self.db.close()
def process_item(self, item, spider):
#保存到数据库
self.sql = "INSERT INTO article_list(id,link,title,doread) VALUES(null,\'%s\',\'%s\',\'%s\')" % (item['link'],item['title'],item['reads'])
self.cursor.execute(self.sql)
self.db.commit()
这里遇到个问题是doread字段,我本来想用reads,但是发现用read或reads,MySQL会报错,应该是关键字不让用,就换用了doread
阶段4
目标:scrapy结合selenium进行网站登录
这一个阶段跟前3个阶段其实没多大关系,主要是为了练习scrapy和selenium的配合,新建一个项目ScrapyAddSelenium,items.py和pipelines.py都用默认的,只编写爬虫代码csdn_post.py 这里尝试自动登录csdn
# -*- coding: utf-8 -*-
import scrapy
from selenium import webdriver
import time
class CsdnPostSpider(scrapy.Spider):
name = 'csdn_post'
allowed_domains = ['csdn.com']
start_urls = ['http://csdn.com/']
def __init__(self):
self.login_cookies = []
self.headers = {
"Referer": "https://passport.csdn.net/login?code = public",
"User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0"}
def get_cookies(self):
cookies = []
browser = webdriver.Firefox()
time.sleep(3)
browser.get('https://passport.csdn.net/login?code=public')
#csdn登录页上先要点击选择桌面登录,然后才能弹出输入用户名和密码窗口
elem_pc = browser.find_element_by_xpath('/html/body/div[1]/div/div/div[1]/div[2]/div[5]/ul/li[2]')
elem_pc.click()
elem_user = browser.find_element_by_xpath('//input[@id="all"]')
print(elem_user)
elem_user.send_keys("xxxxxxxxxxxxxxxxxxxx")
elem_passwd = browser.find_element_by_xpath('//input[@id="password-number"]')
print(elem_passwd)
elem_passwd.send_keys("xxxxxxxxxxxxxxxxxxxxx")
commit = browser.find_element_by_xpath('//button[@class="btn btn-primary"]')
commit.click()
time.sleep(10)
if "CSDN首页" in browser.title:
self.login_cookies = browser.get_cookies()
else:
print("登录失败")
def start_requests(self):
self.get_cookies()
return
print("######开始访问 CSDN#####")
return [scrapy.Request(url='https://www.csdn.net/nav/python',headers=self.headers,cookies=self.login_cookies,callback=self.parse)]
def parse(self, response):
print('~~~~~~~~~parse~~~~~~~~~~~~')
print('是否解析成功',response.text)
这里遇到2个问题,1.是登录页面上要点击选择桌面登录,才会弹出输入用户名和密码界面,这里试验了好久才成功,2.是find_element_by_xpath函数用成了find_elements_by_xpath,所以获取出来一直是列表,一直报错
问题总结:
1.阶段3 MySQL建表时误用了关键字read,一直报错
2.阶段4 selenium登录CSDN要先处理选择桌面登录,才可以进到输入用户名和密码界面
3.阶段4 find_element_by_xpath函数用成了find_elements_by_xpath,所以获取出来一直是列表,一直报错
参考书籍以及博客:
1.https://blog.csdn.net/luanpeng825485697/article/details/78439210
2.《疯狂的python讲义》