开发中常用的几种爬虫,开发中遇到的问题和解决办法,附代码
一、urllib、selenium、BeautifulSoup
python2 和python3 的urlib库是不一样的,在Python2.X中,分urllib和urllib2,但在Python3.X中,都统一合并到urllib中。
使用时根据自己开发环境选择不同的urlib库,以下开发均为python3 环境
一、app:urllib(Fiddler+夜神模拟器)爬取流程大致如下:
1.安装Fiddler、模拟器、app、尽量避开选择最新的app版本
2.配置相同的IP环境和端口,模拟器需要安装数字证书。
3.在模拟器app界面点击需要爬取的页面,在Fiddler中抓包,以下实例均为api+json
4.找到Fiddler中json内容为需要抓取的内容和对应的api接口,即可开始爬虫编写
对于app脱壳破解,没有遇到也没有做进一步研究。
这里有个小问题就是编码问题,需要统一编码格式,否则爬取的数据存在编码错误。
with open(filepath, 'a+', encoding='utf-8') as f:
json_content = json.loads(response.read().decode('utf-8'))
f.write('%d,%s\n' % (num, json_content,))
response.close()
二、网页:urllib 爬虫,
2.1、urllib的IP代理问题
from urllib.request import ProxyHandler, build_opener
proxy = 'xxxxxxxx:xxx'
proxy_handler = ProxyHandler({
'http': 'http://' + proxy,
'https': 'https://' + proxy
})
opener = build_opener(proxy_handler)
response = opener.open(url)
2.2、爬取页面交互式的数据表格
BeautifulSoup+selenium
在开发时不知道为什么xpath不好使了,这里选在用BeautifulSoup。
#获取整个网页的xml信息
soup = BeautifulSoup(driver.page_source, "lxml")
#通过find find_all定位到所需位置
tr = soup.find(r'table', class_=r'table-one').find_all(r'tr')
#表格类数据获取:tr td
for j in tr[1:]:
td = j.find_all('td')
A = td[0].get_text().strip()
B = td[1].get_text().strip()
C = td[2].get_text().strip()
listdata.append([A, B, C])
#通过selenium 点击页面相应位置,或得新的位置标签
driver.find_element_by_xpath('//*[@id="abcd"]/div[1]/div/a[%d]' % (3)).click()
这里需要注意:有些页面在源码中是预留td标签给点击后响应的数据的,有些是刷新之前td标签的,有些是保留原始td再更新一批td标签,还有一些是根据click不同位置,刷新不同td标签
1)预留的td标签可以多次调取click()方法使他们都加载出来,再爬取。
2)对于刷新的td标签,可以不做处理放入循环中,
3)对于保留原始td,再更新td标签的,可以for j in tr[X:]:X为更新的td标签的索引。
4)根据click不同位置,刷新不同td标签,可以观察不同click 页面刷新的td标签,做相应处理。我遇到的是F5是第一份,点击,是第一加第二,再点击是第一和第三分,所以不处理F5页面,直接点击取第一第二,再点击截取第三份。
##页面信息出现定位不准确的时候可以尝试多种定位:find_element_by_xpath、BeautifulSoup等等,有些源码中的空格部分需要加.才能定位的:find_element_by_css_selector(a.link.next.x-x-30)源码中显示为a link next x-x-30
爬取页面截图,长截图和部分截图:
PhantomJS默认截图是长截图,
谷歌、火狐为当前页面显示截图,
长截图:目前谷歌版本已经支持browser.set_window_size(width, height),通过设置width和heighht来达到截取长图,或者selenium:# 向下滚动10000像素js = "document.body.scrollTop=10000",或者直接跳转底部等等。
截图:
第一种:直接放代码吧,
# -*- coding:utf-8 -*-
import time
from PIL import Image
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
"""
全图和截图
"""
url = ''
offset = 2626
coptions = webdriver.ChromeOptions()
coptions.add_argument('-headless')
# coptions.add_argument("--proxy-server=http://116.62.184.163:3128")
browser = webdriver.Chrome(chrome_options=coptions)
browser.set_page_load_timeout(3000)
browser.set_script_timeout(3000)
while 1:
if offset <= 2626:
try:
browser.get(url=url + str(offset))
a = browser.find_element_by_xpath("")
a.click()
time.sleep(1)
a.click()
time.sleep(1)
a.click()
time.sleep(1)
WebDriverWait(browser, 20, 0.5).until(
lambda browser: browser.find_element_by_class_name('BBBBB')
)
eles = browser.find_elements_by_xpath("//html")
locs = []
width = 1800
height = 2500
browser.set_window_size(width, height)
#全图
browser.save_screenshot("%d.png" % (offset))
time.sleep(1)
element = browser.find_element_by_class_name("BBBBB")
location = element.location
size = element.size
left = element.location['x']
top = element.location['y']
right = element.location['x'] + element.size['width']
bottom = element.location['y'] + element.size['height']
#截图
im = Image.open("%d.png" % (offset))
im = im.crop((left, top, right, bottom))
im.save("C:/Users/Administrator/Desktop/leisu/png/%d.png" % (offset))
offset += 1
except :
offset -= 1
else:
browser.quit()
break
第二种:直接放代码吧,
# -*- coding:utf-8 -*-
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
# 2626
from selenium.webdriver.support import ui
"""
截图
"""
url = ''
offset = 2626
coptions = webdriver.ChromeOptions()
coptions.add_argument('-headless')
# coptions.add_argument("--proxy-server=http://116.62.184.163:3128")
browser = webdriver.Chrome(chrome_options=coptions)
browser.set_page_load_timeout(3000)
browser.set_script_timeout(3000)
while 1:
if offset >= 2626:
browser.get(url=url + str(offset))
a = browser.find_element_by_xpath("")
a.click()
WebDriverWait(browser, 10, 0.5).until(
lambda browser: browser.find_element_by_class_name('BBBBB')
)
time.sleep(1)
b = browser.find_element_by_xpath('')
# 全屏
# width = 1606
# height = 2500
# browser.set_window_size(width, height)
# browser.save_screenshot("%d.png" % (offset))
b.screenshot("%d.png" % (offset))
offset -= 1
time.sleep(1)
else:
browser.quit()
break
二、scrapy:
3##简单的scrapy编写流程:
1.pip install scrapy:
2.scrapy startproject xxxxxxxx
3.根据需要设置setting
4。编写iteam
5.编写spider
6.scrapy runspider spider.py或scrapy crawl spider
7.scrapy 的中断与重启,
方法一:
1、首先cd进入到scrapy项目里(当然你也可以通过编写脚本Python文件直接在pycharm中运行)
2、在scrapy项目里创建保存记录信息的文件夹
3、执行命令:scrapy crawl 爬虫名称 -s JOBDIR=保存记录信息的路径
如:scrapy crawl cnblogs -s JOBDIR=zant/001
执行命令会启动指定爬虫,并且记录状态到指定目录,按键盘上的ctrl+c停止爬虫,停止后我们看一下记录文件夹,会多出3个文件,其中的requests.queue文件夹里的p0文件就是URL记录文件,这个文件存在就说明还有未完成的URL,当所有URL完成后会自动删除此文件当我们重新执行命令:scrapy crawl cnblogs -s JOBDIR=zant/001 时爬虫会根据p0文件从停止的地方开始继续爬取。
方法二:
在settings.py文件里加入下面的代码:
JOBDIR='sharejs.com'
使用命令scrapy crawl somespider,就会自动生成一个sharejs.com的目录,然后将工作列表放到这个文件夹里
###scrapy爬取某一标签下的所有信息:
all_info = each.xpath(r"")
all_ = all_info.xpath(r"string(.)").extract()
alldesc = ""
for allpool in all_:
allpool_ = allpool.strip()
alldesc = alldesc + allpool_
item["aaaa"] = alldesc
### middlewares中为RandomUserAgent和RandomProxy
### PlayspiderPipeline为文件写入
scrapy+selenium 和scrapy 的动态代理和随机User-Agent
其余代码整理后上传至github。